• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #define MLOG_TAG "MediaLibraryNapi"
17 
18 #include "media_library_napi.h"
19 #include <fcntl.h>
20 #include <sys/sendfile.h>
21 
22 #include "directory_ex.h"
23 #include "file_ex.h"
24 #include "hitrace_meter.h"
25 #include "media_file_uri.h"
26 #include "media_file_utils.h"
27 #include "medialibrary_client_errno.h"
28 #include "medialibrary_asset_operations.h"
29 #include "medialibrary_data_manager.h"
30 #include "medialibrary_db_const.h"
31 #include "medialibrary_errno.h"
32 #include "medialibrary_napi_log.h"
33 #include "medialibrary_peer_info.h"
34 #include "medialibrary_tracer.h"
35 #include "media_column.h"
36 #include "permission_utils.h"
37 #include "photo_album_column.h"
38 #include "photo_album_napi.h"
39 #include "result_set_utils.h"
40 #include "smart_album_napi.h"
41 #include "string_ex.h"
42 #include "string_wrapper.h"
43 #include "userfile_client.h"
44 #include "uv.h"
45 
46 using namespace std;
47 using namespace OHOS::AppExecFwk;
48 using namespace OHOS::NativeRdb;
49 using namespace OHOS::DataShare;
50 
51 namespace OHOS {
52 namespace Media {
53 using ChangeType = AAFwk::ChangeInfo::ChangeType;
54 thread_local unique_ptr<ChangeListenerNapi> g_listObj = nullptr;
55 const int32_t NUM_2 = 2;
56 const int32_t NUM_3 = 3;
57 const string DATE_FUNCTION = "DATE(";
58 
59 mutex MediaLibraryNapi::sUserFileClientMutex_;
60 mutex MediaLibraryNapi::sOnOffMutex_;
61 string ChangeListenerNapi::trashAlbumUri_;
62 static map<string, ListenerType> ListenerTypeMaps = {
63     {"audioChange", AUDIO_LISTENER},
64     {"videoChange", VIDEO_LISTENER},
65     {"imageChange", IMAGE_LISTENER},
66     {"fileChange", FILE_LISTENER},
67     {"albumChange", ALBUM_LISTENER},
68     {"deviceChange", DEVICE_LISTENER},
69     {"remoteFileChange", REMOTEFILE_LISTENER}
70 };
71 
72 const std::string SUBTYPE = "subType";
73 const std::string PAH_SUBTYPE = "subtype";
74 const std::string CAMERA_SHOT_KEY = "cameraShotKey";
75 const std::map<std::string, std::string> PHOTO_CREATE_OPTIONS_PARAM = {
76     { SUBTYPE, PhotoColumn::PHOTO_SUBTYPE },
77     { CAMERA_SHOT_KEY, PhotoColumn::CAMERA_SHOT_KEY },
78     { PAH_SUBTYPE, PhotoColumn::PHOTO_SUBTYPE }
79 
80 };
81 
82 const std::string TITLE = "title";
83 const std::map<std::string, std::string> CREATE_OPTIONS_PARAM = {
84     { TITLE, MediaColumn::MEDIA_TITLE }
85 };
86 
87 thread_local napi_ref MediaLibraryNapi::sConstructor_ = nullptr;
88 thread_local napi_ref MediaLibraryNapi::sMediaTypeEnumRef_ = nullptr;
89 thread_local napi_ref MediaLibraryNapi::sDirectoryEnumRef_ = nullptr;
90 thread_local napi_ref MediaLibraryNapi::sVirtualAlbumTypeEnumRef_ = nullptr;
91 thread_local napi_ref MediaLibraryNapi::sFileKeyEnumRef_ = nullptr;
92 thread_local napi_ref MediaLibraryNapi::sPrivateAlbumEnumRef_ = nullptr;
93 thread_local napi_ref MediaLibraryNapi::sPositionTypeEnumRef_ = nullptr;
94 thread_local napi_ref MediaLibraryNapi::sPhotoSubType_ = nullptr;
95 using CompleteCallback = napi_async_complete_callback;
96 using Context = MediaLibraryAsyncContext* ;
97 
98 thread_local napi_ref MediaLibraryNapi::userFileMgrConstructor_ = nullptr;
99 thread_local napi_ref MediaLibraryNapi::photoAccessHelperConstructor_ = nullptr;
100 thread_local napi_ref MediaLibraryNapi::sUserFileMgrFileKeyEnumRef_ = nullptr;
101 thread_local napi_ref MediaLibraryNapi::sAudioKeyEnumRef_ = nullptr;
102 thread_local napi_ref MediaLibraryNapi::sImageVideoKeyEnumRef_ = nullptr;
103 thread_local napi_ref MediaLibraryNapi::sPhotoKeysEnumRef_ = nullptr;
104 thread_local napi_ref MediaLibraryNapi::sAlbumKeyEnumRef_ = nullptr;
105 thread_local napi_ref MediaLibraryNapi::sAlbumType_ = nullptr;
106 thread_local napi_ref MediaLibraryNapi::sAlbumSubType_ = nullptr;
107 thread_local napi_ref MediaLibraryNapi::sNotifyType_ = nullptr;
108 thread_local napi_ref MediaLibraryNapi::sDefaultChangeUriRef_ = nullptr;
109 constexpr int32_t DEFAULT_REFCOUNT = 1;
110 constexpr int32_t DEFAULT_ALBUM_COUNT = 1;
MediaLibraryNapi()111 MediaLibraryNapi::MediaLibraryNapi()
112     : env_(nullptr) {}
113 
114 MediaLibraryNapi::~MediaLibraryNapi() = default;
115 
MediaLibraryNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)116 void MediaLibraryNapi::MediaLibraryNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
117 {
118     MediaLibraryNapi *mediaLibrary = reinterpret_cast<MediaLibraryNapi*>(nativeObject);
119     if (mediaLibrary != nullptr) {
120         delete mediaLibrary;
121         mediaLibrary = nullptr;
122     }
123 }
124 
Init(napi_env env,napi_value exports)125 napi_value MediaLibraryNapi::Init(napi_env env, napi_value exports)
126 {
127     napi_property_descriptor media_library_properties[] = {
128         DECLARE_NAPI_FUNCTION("getPublicDirectory", JSGetPublicDirectory),
129         DECLARE_NAPI_FUNCTION("getFileAssets", JSGetFileAssets),
130         DECLARE_NAPI_FUNCTION("getAlbums", JSGetAlbums),
131         DECLARE_NAPI_FUNCTION("createAsset", JSCreateAsset),
132         DECLARE_NAPI_FUNCTION("deleteAsset", JSDeleteAsset),
133         DECLARE_NAPI_FUNCTION("on", JSOnCallback),
134         DECLARE_NAPI_FUNCTION("off", JSOffCallback),
135         DECLARE_NAPI_FUNCTION("release", JSRelease),
136         DECLARE_NAPI_FUNCTION("getSmartAlbum", JSGetSmartAlbums),
137         DECLARE_NAPI_FUNCTION("getPrivateAlbum", JSGetPrivateAlbum),
138         DECLARE_NAPI_FUNCTION("createSmartAlbum", JSCreateSmartAlbum),
139         DECLARE_NAPI_FUNCTION("deleteSmartAlbum", JSDeleteSmartAlbum),
140         DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
141         DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
142         DECLARE_NAPI_FUNCTION("storeMediaAsset", JSStoreMediaAsset),
143         DECLARE_NAPI_FUNCTION("startImagePreview", JSStartImagePreview),
144     };
145     napi_property_descriptor static_prop[] = {
146         DECLARE_NAPI_STATIC_FUNCTION("getMediaLibrary", GetMediaLibraryNewInstance),
147         DECLARE_NAPI_STATIC_FUNCTION("getMediaLibraryAsync", GetMediaLibraryNewInstanceAsync),
148         DECLARE_NAPI_PROPERTY("MediaType", CreateMediaTypeEnum(env)),
149         DECLARE_NAPI_PROPERTY("FileKey", CreateFileKeyEnum(env)),
150         DECLARE_NAPI_PROPERTY("DirectoryType", CreateDirectoryTypeEnum(env)),
151         DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env))
152     };
153     napi_value ctorObj;
154     napi_status status = napi_define_class(env, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
155         MediaLibraryNapiConstructor, nullptr,
156         sizeof(media_library_properties) / sizeof(media_library_properties[PARAM0]),
157         media_library_properties, &ctorObj);
158     if (status == napi_ok) {
159         int32_t refCount = 1;
160         if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
161             status = napi_set_named_property(env, exports, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), ctorObj);
162             if (status == napi_ok && napi_define_properties(env, exports,
163                 sizeof(static_prop) / sizeof(static_prop[PARAM0]), static_prop) == napi_ok) {
164                 return exports;
165             }
166         }
167     }
168     return nullptr;
169 }
170 
UserFileMgrInit(napi_env env,napi_value exports)171 napi_value MediaLibraryNapi::UserFileMgrInit(napi_env env, napi_value exports)
172 {
173     NapiClassInfo info = {
174         USERFILE_MGR_NAPI_CLASS_NAME,
175         &userFileMgrConstructor_,
176         MediaLibraryNapiConstructor,
177         {
178             DECLARE_NAPI_FUNCTION("getPhotoAssets", JSGetPhotoAssets),
179             DECLARE_NAPI_FUNCTION("getAudioAssets", JSGetAudioAssets),
180             DECLARE_NAPI_FUNCTION("getPhotoAlbums", JSGetPhotoAlbums),
181             DECLARE_NAPI_FUNCTION("createPhotoAsset", UserFileMgrCreatePhotoAsset),
182             DECLARE_NAPI_FUNCTION("createAudioAsset", UserFileMgrCreateAudioAsset),
183             DECLARE_NAPI_FUNCTION("delete", UserFileMgrTrashAsset),
184             DECLARE_NAPI_FUNCTION("on", UserFileMgrOnCallback),
185             DECLARE_NAPI_FUNCTION("off", UserFileMgrOffCallback),
186             DECLARE_NAPI_FUNCTION("getPrivateAlbum", UserFileMgrGetPrivateAlbum),
187             DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
188             DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
189             DECLARE_NAPI_FUNCTION("release", JSRelease),
190             DECLARE_NAPI_FUNCTION("createAlbum", CreatePhotoAlbum),
191             DECLARE_NAPI_FUNCTION("deleteAlbums", DeletePhotoAlbums),
192             DECLARE_NAPI_FUNCTION("getAlbums", GetPhotoAlbums),
193             DECLARE_NAPI_FUNCTION("getPhotoIndex", JSGetPhotoIndex),
194         }
195     };
196     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
197 
198     const vector<napi_property_descriptor> staticProps = {
199         DECLARE_NAPI_STATIC_FUNCTION("getUserFileMgr", GetUserFileMgr),
200         DECLARE_NAPI_STATIC_FUNCTION("getUserFileMgrAsync", GetUserFileMgrAsync),
201         DECLARE_NAPI_PROPERTY("FileType", CreateMediaTypeUserFileEnum(env)),
202         DECLARE_NAPI_PROPERTY("FileKey", UserFileMgrCreateFileKeyEnum(env)),
203         DECLARE_NAPI_PROPERTY("AudioKey", CreateAudioKeyEnum(env)),
204         DECLARE_NAPI_PROPERTY("ImageVideoKey", CreateImageVideoKeyEnum(env)),
205         DECLARE_NAPI_PROPERTY("AlbumKey", CreateAlbumKeyEnum(env)),
206         DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env)),
207         DECLARE_NAPI_PROPERTY("AlbumType", CreateAlbumTypeEnum(env)),
208         DECLARE_NAPI_PROPERTY("AlbumSubType", CreateAlbumSubTypeEnum(env)),
209         DECLARE_NAPI_PROPERTY("PositionType", CreatePositionTypeEnum(env)),
210         DECLARE_NAPI_PROPERTY("PhotoSubType", CreatePhotoSubTypeEnum(env)),
211         DECLARE_NAPI_PROPERTY("NotifyType", CreateNotifyTypeEnum(env)),
212         DECLARE_NAPI_PROPERTY("DefaultChangeUri", CreateDefaultChangeUriEnum(env))
213     };
214     MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
215     return exports;
216 }
217 
PhotoAccessHelperInit(napi_env env,napi_value exports)218 napi_value MediaLibraryNapi::PhotoAccessHelperInit(napi_env env, napi_value exports)
219 {
220     NapiClassInfo info = {
221         PHOTOACCESSHELPER_NAPI_CLASS_NAME,
222         &photoAccessHelperConstructor_,
223         MediaLibraryNapiConstructor,
224         {
225             DECLARE_NAPI_FUNCTION("getAssets", PhotoAccessGetPhotoAssets),
226             DECLARE_NAPI_FUNCTION("createAsset", PhotoAccessHelperCreatePhotoAsset),
227             DECLARE_NAPI_FUNCTION("registerChange", PhotoAccessHelperOnCallback),
228             DECLARE_NAPI_FUNCTION("unRegisterChange", PhotoAccessHelperOffCallback),
229             DECLARE_NAPI_FUNCTION("deleteAssets", PhotoAccessHelperTrashAsset),
230             DECLARE_NAPI_FUNCTION("release", JSRelease),
231             DECLARE_NAPI_FUNCTION("createAlbum", PhotoAccessCreatePhotoAlbum),
232             DECLARE_NAPI_FUNCTION("deleteAlbums", PhotoAccessDeletePhotoAlbums),
233             DECLARE_NAPI_FUNCTION("getAlbums", PhotoAccessGetPhotoAlbums),
234             DECLARE_NAPI_FUNCTION("getPhotoIndex", PhotoAccessGetPhotoIndex),
235         }
236     };
237     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
238 
239     const vector<napi_property_descriptor> staticProps = {
240         DECLARE_NAPI_STATIC_FUNCTION("getPhotoAccessHelper", GetPhotoAccessHelper),
241         DECLARE_NAPI_STATIC_FUNCTION("getPhotoAccessHelperAsync", GetPhotoAccessHelperAsync),
242         DECLARE_NAPI_PROPERTY("PhotoType", CreateMediaTypeUserFileEnum(env)),
243         DECLARE_NAPI_PROPERTY("AlbumKeys", CreateAlbumKeyEnum(env)),
244         DECLARE_NAPI_PROPERTY("AlbumType", CreateAlbumTypeEnum(env)),
245         DECLARE_NAPI_PROPERTY("PhotoKeys", CreatePhotoKeysEnum(env)),
246         DECLARE_NAPI_PROPERTY("AlbumSubtype", CreateAlbumSubTypeEnum(env)),
247         DECLARE_NAPI_PROPERTY("PositionType", CreatePositionTypeEnum(env)),
248         DECLARE_NAPI_PROPERTY("PhotoSubtype", CreatePhotoSubTypeEnum(env)),
249         DECLARE_NAPI_PROPERTY("NotifyType", CreateNotifyTypeEnum(env)),
250         DECLARE_NAPI_PROPERTY("DefaultChangeUri", CreateDefaultChangeUriEnum(env))
251     };
252     MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
253     return exports;
254 }
255 
CheckWhetherAsync(napi_env env,napi_callback_info info,bool & isAsync)256 static napi_status CheckWhetherAsync(napi_env env, napi_callback_info info, bool &isAsync)
257 {
258     isAsync = false;
259     size_t argc = ARGS_TWO;
260     napi_value argv[ARGS_TWO] = {0};
261     napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
262     if (status != napi_ok) {
263         NAPI_ERR_LOG("Error while obtaining js environment information");
264         return status;
265     }
266 
267     if (argc == ARGS_ONE) {
268         return napi_ok;
269     } else if (argc == ARGS_TWO) {
270         napi_valuetype valueType = napi_undefined;
271         status = napi_typeof(env, argv[ARGS_ONE], &valueType);
272         if (status != napi_ok) {
273             NAPI_ERR_LOG("Error while obtaining js environment information");
274             return status;
275         }
276         if (valueType == napi_boolean) {
277             isAsync = true;
278         }
279         status = napi_get_value_bool(env, argv[ARGS_ONE], &isAsync);
280         return status;
281     } else {
282         NAPI_ERR_LOG("argc %{public}d, is invalid", static_cast<int>(argc));
283         return napi_invalid_arg;
284     }
285 }
286 
287 // Constructor callback
MediaLibraryNapiConstructor(napi_env env,napi_callback_info info)288 napi_value MediaLibraryNapi::MediaLibraryNapiConstructor(napi_env env, napi_callback_info info)
289 {
290     napi_status status;
291     napi_value result = nullptr;
292     napi_value thisVar = nullptr;
293     MediaLibraryTracer tracer;
294 
295     tracer.Start("MediaLibraryNapiConstructor");
296 
297     NAPI_CALL(env, napi_get_undefined(env, &result));
298     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
299     if (status != napi_ok || thisVar == nullptr) {
300         NAPI_ERR_LOG("Error while obtaining js environment information, status: %{public}d", status);
301         return result;
302     }
303 
304     unique_ptr<MediaLibraryNapi> obj = make_unique<MediaLibraryNapi>();
305     if (obj == nullptr) {
306         return result;
307     }
308     obj->env_ = env;
309     // Initialize the ChangeListener object
310     if (g_listObj == nullptr) {
311         g_listObj = make_unique<ChangeListenerNapi>(env);
312     }
313 
314     bool isAsync = false;
315     NAPI_CALL(env, CheckWhetherAsync(env, info, isAsync));
316     if (!isAsync) {
317         unique_lock<mutex> helperLock(sUserFileClientMutex_);
318         if (!UserFileClient::IsValid()) {
319             UserFileClient::Init(env, info);
320             if (!UserFileClient::IsValid()) {
321                 NAPI_ERR_LOG("UserFileClient creation failed");
322                 return result;
323             }
324         }
325         helperLock.unlock();
326     }
327 
328     status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
329                        MediaLibraryNapi::MediaLibraryNapiDestructor, nullptr, nullptr);
330     if (status == napi_ok) {
331         obj.release();
332         return thisVar;
333     } else {
334         NAPI_ERR_LOG("Failed to wrap the native media lib client object with JS, status: %{public}d", status);
335     }
336 
337     return result;
338 }
339 
CheckWhetherInitSuccess(napi_env env,napi_value value,bool checkIsValid)340 static bool CheckWhetherInitSuccess(napi_env env, napi_value value, bool checkIsValid)
341 {
342     napi_value propertyNames;
343     uint32_t propertyLength;
344     napi_valuetype valueType = napi_undefined;
345     NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false);
346     if (valueType != napi_object) {
347         return false;
348     }
349 
350     NAPI_CALL_BASE(env, napi_get_property_names(env, value, &propertyNames), false);
351     NAPI_CALL_BASE(env, napi_get_array_length(env, propertyNames, &propertyLength), false);
352     if (propertyLength == 0) {
353         return false;
354     }
355     if (checkIsValid && (!UserFileClient::IsValid())) {
356         NAPI_ERR_LOG("UserFileClient is not valid");
357         return false;
358     }
359     return true;
360 }
361 
CreateNewInstance(napi_env env,napi_callback_info info,napi_ref ref,bool isAsync=false)362 static napi_value CreateNewInstance(napi_env env, napi_callback_info info, napi_ref ref,
363     bool isAsync = false)
364 {
365     constexpr size_t ARG_CONTEXT = 1;
366     size_t argc = ARG_CONTEXT;
367     napi_value argv[ARGS_TWO] = {0};
368 
369     napi_value thisVar = nullptr;
370     napi_value ctor = nullptr;
371     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
372     NAPI_CALL(env, napi_get_reference_value(env, ref, &ctor));
373 
374     if (isAsync) {
375         argc = ARGS_TWO;
376         NAPI_CALL(env, napi_get_boolean(env, true, &argv[ARGS_ONE]));
377         argv[ARGS_ONE] = argv[ARG_CONTEXT];
378     }
379 
380     napi_value result = nullptr;
381     NAPI_CALL(env, napi_new_instance(env, ctor, argc, argv, &result));
382     if (!CheckWhetherInitSuccess(env, result, !isAsync)) {
383         NAPI_ERR_LOG("Init MediaLibrary Instance is failed");
384         NAPI_CALL(env, napi_get_undefined(env, &result));
385     }
386     return result;
387 }
388 
GetMediaLibraryNewInstance(napi_env env,napi_callback_info info)389 napi_value MediaLibraryNapi::GetMediaLibraryNewInstance(napi_env env, napi_callback_info info)
390 {
391     MediaLibraryTracer tracer;
392     tracer.Start("getMediaLibrary");
393 
394     napi_value result = nullptr;
395     napi_value ctor;
396     size_t argc = ARGS_ONE;
397     napi_value argv[ARGS_ONE] = {0};
398     napi_value thisVar = nullptr;
399     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
400     napi_status status = napi_get_reference_value(env, sConstructor_, &ctor);
401     if (status == napi_ok) {
402         status = napi_new_instance(env, ctor, argc, argv, &result);
403         if (status == napi_ok) {
404             if (CheckWhetherInitSuccess(env, result, true)) {
405                 return result;
406             } else {
407                 NAPI_ERR_LOG("Init MediaLibrary Instance is failed");
408             }
409         } else {
410             NAPI_ERR_LOG("New instance could not be obtained status: %{public}d", status);
411         }
412     } else {
413         NAPI_ERR_LOG("status = %{public}d", status);
414     }
415 
416     napi_get_undefined(env, &result);
417     return result;
418 }
419 
GetMediaLibraryAsyncExecute(napi_env env,void * data)420 static void GetMediaLibraryAsyncExecute(napi_env env, void *data)
421 {
422     MediaLibraryTracer tracer;
423     tracer.Start("GetMediaLibraryAsyncExecute");
424 
425     MediaLibraryInitContext *asyncContext = static_cast<MediaLibraryInitContext *>(data);
426     if (asyncContext == nullptr) {
427         NAPI_ERR_LOG("Async context is null");
428         asyncContext->error = ERR_INVALID_OUTPUT;
429         return;
430     }
431 
432     asyncContext->error = ERR_DEFAULT;
433     unique_lock<mutex> helperLock(MediaLibraryNapi::sUserFileClientMutex_);
434     if (!UserFileClient::IsValid()) {
435         UserFileClient::Init(asyncContext->token_, true);
436         if (!UserFileClient::IsValid()) {
437             NAPI_ERR_LOG("UserFileClient creation failed");
438             asyncContext->error = ERR_INVALID_OUTPUT;
439             return;
440         }
441     }
442     helperLock.unlock();
443 }
444 
GetMediaLibraryAsyncComplete(napi_env env,napi_status status,void * data)445 static void GetMediaLibraryAsyncComplete(napi_env env, napi_status status, void *data)
446 {
447     MediaLibraryInitContext *context = static_cast<MediaLibraryInitContext *>(data);
448     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
449     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
450     jsContext->status = false;
451 
452     napi_value result = nullptr;
453     if (napi_get_reference_value(env, context->resultRef_, &result) != napi_ok) {
454         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
455             "Get result from context ref failed");
456     }
457     napi_valuetype valueType;
458     if (napi_typeof(env, result, &valueType) != napi_ok || valueType != napi_object) {
459         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
460             "Get result type failed " + to_string((int) valueType));
461     }
462 
463     if (context->error == ERR_DEFAULT) {
464         jsContext->data = result;
465         jsContext->status = true;
466         napi_get_undefined(env, &jsContext->error);
467     } else {
468         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
469             "Failed to get MediaLibrary");
470         napi_get_undefined(env, &jsContext->data);
471     }
472 
473     if (context->work != nullptr) {
474         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
475             context->work, *jsContext);
476     }
477     napi_delete_reference(env, context->resultRef_);
478     delete context;
479 }
480 
GetMediaLibraryNewInstanceAsync(napi_env env,napi_callback_info info)481 napi_value MediaLibraryNapi::GetMediaLibraryNewInstanceAsync(napi_env env, napi_callback_info info)
482 {
483     MediaLibraryTracer tracer;
484     tracer.Start("getMediaLibraryAsync");
485 
486     unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
487     if (asyncContext == nullptr) {
488         NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
489         return nullptr;
490     }
491     asyncContext->argc = ARGS_TWO;
492     napi_value thisVar = nullptr;
493     NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
494         &thisVar, nullptr));
495 
496     napi_value result = CreateNewInstance(env, info, sConstructor_, true);
497     napi_valuetype valueType;
498     NAPI_CALL(env, napi_typeof(env, result, &valueType));
499     if (valueType == napi_undefined) {
500         NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
501         return nullptr;
502     }
503     NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
504     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
505 
506     bool isStage = false;
507     NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
508     if (isStage) {
509         asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
510     } else {
511         asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
512     }
513 
514     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetUserFileMgrAsync",
515         GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
516 }
517 
GetUserFileMgr(napi_env env,napi_callback_info info)518 napi_value MediaLibraryNapi::GetUserFileMgr(napi_env env, napi_callback_info info)
519 {
520     MediaLibraryTracer tracer;
521     tracer.Start("getUserFileManager");
522 
523     if (!MediaLibraryNapiUtils::IsSystemApp()) {
524         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can get userFileManger instance");
525         return nullptr;
526     }
527 
528     return CreateNewInstance(env, info, userFileMgrConstructor_);
529 }
530 
GetUserFileMgrAsync(napi_env env,napi_callback_info info)531 napi_value MediaLibraryNapi::GetUserFileMgrAsync(napi_env env, napi_callback_info info)
532 {
533     MediaLibraryTracer tracer;
534     tracer.Start("getUserFileManagerAsync");
535 
536     if (!MediaLibraryNapiUtils::IsSystemApp()) {
537         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can get userFileManger instance");
538         return nullptr;
539     }
540 
541     unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
542     if (asyncContext == nullptr) {
543         NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
544         return nullptr;
545     }
546     asyncContext->argc = ARGS_TWO;
547     napi_value thisVar = nullptr;
548     NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
549         &thisVar, nullptr));
550 
551     napi_value result = CreateNewInstance(env, info, userFileMgrConstructor_, true);
552     napi_valuetype valueType;
553     NAPI_CALL(env, napi_typeof(env, result, &valueType));
554     if (valueType == napi_undefined) {
555         NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
556         return nullptr;
557     }
558     NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
559     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
560 
561     bool isStage = false;
562     NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
563     if (isStage) {
564         asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
565     } else {
566         asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
567     }
568 
569     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetUserFileMgrAsync",
570         GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
571 }
572 
GetPhotoAccessHelper(napi_env env,napi_callback_info info)573 napi_value MediaLibraryNapi::GetPhotoAccessHelper(napi_env env, napi_callback_info info)
574 {
575     MediaLibraryTracer tracer;
576     tracer.Start("GetPhotoAccessHelper");
577 
578     return CreateNewInstance(env, info, photoAccessHelperConstructor_);
579 }
580 
GetPhotoAccessHelperAsync(napi_env env,napi_callback_info info)581 napi_value MediaLibraryNapi::GetPhotoAccessHelperAsync(napi_env env, napi_callback_info info)
582 {
583     MediaLibraryTracer tracer;
584     tracer.Start("GetPhotoAccessHelperAsync");
585 
586     unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
587     if (asyncContext == nullptr) {
588         NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
589         return nullptr;
590     }
591     asyncContext->argc = ARGS_TWO;
592     napi_value thisVar = nullptr;
593     NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
594         &thisVar, nullptr));
595 
596     napi_value result = CreateNewInstance(env, info, photoAccessHelperConstructor_, true);
597     napi_valuetype valueType;
598     NAPI_CALL(env, napi_typeof(env, result, &valueType));
599     if (valueType == napi_undefined) {
600         NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
601         return nullptr;
602     }
603     NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
604     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
605 
606     bool isStage = false;
607     NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
608     if (isStage) {
609         asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
610     } else {
611         asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
612     }
613 
614     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAccessHelperAsync",
615         GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
616 }
617 
AddIntegerNamedProperty(napi_env env,napi_value object,const string & name,int32_t enumValue)618 static napi_status AddIntegerNamedProperty(napi_env env, napi_value object,
619     const string &name, int32_t enumValue)
620 {
621     napi_value enumNapiValue;
622     napi_status status = napi_create_int32(env, enumValue, &enumNapiValue);
623     if (status == napi_ok) {
624         status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
625     }
626     return status;
627 }
628 
CreateNumberEnumProperty(napi_env env,vector<string> properties,napi_ref & ref,int32_t offset=0)629 static napi_value CreateNumberEnumProperty(napi_env env, vector<string> properties, napi_ref &ref, int32_t offset = 0)
630 {
631     napi_value result = nullptr;
632     NAPI_CALL(env, napi_create_object(env, &result));
633     for (size_t i = 0; i < properties.size(); i++) {
634         NAPI_CALL(env, AddIntegerNamedProperty(env, result, properties[i], i + offset));
635     }
636     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
637     return result;
638 }
639 
AddStringNamedProperty(napi_env env,napi_value object,const string & name,string enumValue)640 static napi_status AddStringNamedProperty(napi_env env, napi_value object,
641     const string &name, string enumValue)
642 {
643     napi_value enumNapiValue;
644     napi_status status = napi_create_string_utf8(env, enumValue.c_str(), NAPI_AUTO_LENGTH, &enumNapiValue);
645     if (status == napi_ok) {
646         status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
647     }
648     return status;
649 }
650 
CreateStringEnumProperty(napi_env env,vector<pair<string,string>> properties,napi_ref & ref)651 static napi_value CreateStringEnumProperty(napi_env env, vector<pair<string, string>> properties, napi_ref &ref)
652 {
653     napi_value result = nullptr;
654     NAPI_CALL(env, napi_create_object(env, &result));
655     for (unsigned int i = 0; i < properties.size(); i++) {
656         NAPI_CALL(env, AddStringNamedProperty(env, result, properties[i].first, properties[i].second));
657     }
658     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
659     return result;
660 }
661 
DealWithCommonParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err,bool & present)662 static void DealWithCommonParam(napi_env env, napi_value arg,
663     const MediaLibraryAsyncContext &context, bool &err, bool &present)
664 {
665     MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
666     CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
667     char buffer[PATH_MAX];
668     size_t res = 0;
669     napi_value property = nullptr;
670     napi_has_named_property(env, arg, "selections", &present);
671     if (present) {
672         if ((napi_get_named_property(env, arg, "selections", &property) != napi_ok) ||
673             (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
674             NAPI_ERR_LOG("Could not get the string argument!");
675             err = true;
676             return;
677         } else {
678             asyncContext->selection = buffer;
679             CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
680         }
681         present = false;
682     }
683 
684     napi_has_named_property(env, arg, "order", &present);
685     if (present) {
686         if ((napi_get_named_property(env, arg, "order", &property) != napi_ok) ||
687             (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
688             NAPI_ERR_LOG("Could not get the string argument!");
689             err = true;
690             return;
691         } else {
692             asyncContext->order = buffer;
693             CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
694         }
695         present = false;
696     }
697 
698     napi_has_named_property(env, arg, "uri", &present);
699     if (present) {
700         if ((napi_get_named_property(env, arg, "uri", &property) != napi_ok)||
701             (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
702             NAPI_ERR_LOG("Could not get the uri property!");
703             err = true;
704             return;
705         }
706         asyncContext->uri = buffer;
707         CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
708         present = false;
709     }
710 
711     napi_has_named_property(env, arg, "networkId", &present);
712     if (present) {
713         if ((napi_get_named_property(env, arg, "networkId", &property) != napi_ok) ||
714             (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
715             NAPI_ERR_LOG("Could not get the networkId string argument!");
716             err = true;
717             return;
718         } else {
719             asyncContext->networkId = buffer;
720             CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
721         }
722         present = false;
723     }
724     napi_has_named_property(env, arg, "extendArgs", &present);
725     if (present) {
726         if ((napi_get_named_property(env, arg, "extendArgs", &property) != napi_ok) ||
727             (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
728             NAPI_ERR_LOG("Could not get the extendArgs string argument!");
729             err = true;
730             return;
731         } else {
732             asyncContext->extendArgs = buffer;
733             CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
734         }
735         present = false;
736     }
737 }
738 
GetFetchOptionsParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err)739 static void GetFetchOptionsParam(napi_env env, napi_value arg, const MediaLibraryAsyncContext &context, bool &err)
740 {
741     MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
742     CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
743     napi_value property = nullptr;
744     napi_value stringItem = nullptr;
745     bool present = false;
746     DealWithCommonParam(env, arg, context, err, present);
747     napi_has_named_property(env, arg, "selectionArgs", &present);
748     if (present && napi_get_named_property(env, arg, "selectionArgs", &property) == napi_ok) {
749         uint32_t len = 0;
750         napi_get_array_length(env, property, &len);
751         char buffer[PATH_MAX];
752         for (size_t i = 0; i < len; i++) {
753             napi_get_element(env, property, i, &stringItem);
754             size_t res = 0;
755             napi_get_value_string_utf8(env, stringItem, buffer, PATH_MAX, &res);
756             asyncContext->selectionArgs.push_back(string(buffer));
757             CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
758         }
759     } else {
760         NAPI_ERR_LOG("Could not get the string argument!");
761         err = true;
762     }
763 }
764 
ConvertJSArgsToNative(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)765 static napi_value ConvertJSArgsToNative(napi_env env, size_t argc, const napi_value argv[],
766     MediaLibraryAsyncContext &asyncContext)
767 {
768     bool err = false;
769     const int32_t refCount = 1;
770     auto context = &asyncContext;
771 
772     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
773     for (size_t i = PARAM0; i < argc; i++) {
774         napi_valuetype valueType = napi_undefined;
775         napi_typeof(env, argv[i], &valueType);
776 
777         if (i == PARAM0 && valueType == napi_object) {
778             GetFetchOptionsParam(env, argv[PARAM0], asyncContext, err);
779         } else if (i == PARAM0 && valueType == napi_function) {
780             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
781             break;
782         } else if (i == PARAM1 && valueType == napi_function) {
783             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
784             break;
785         } else {
786             NAPI_ASSERT(env, false, "type mismatch");
787         }
788         if (err) {
789             NAPI_ERR_LOG("fetch options retrieval failed, err: %{public}d", err);
790             NAPI_ASSERT(env, false, "type mismatch");
791         }
792     }
793 
794     // Return true napi_value if params are successfully obtained
795     napi_value result;
796     napi_get_boolean(env, true, &result);
797     return result;
798 }
799 
GetPublicDirectoryExecute(napi_env env,void * data)800 static void GetPublicDirectoryExecute(napi_env env, void *data)
801 {
802     MediaLibraryTracer tracer;
803     tracer.Start("GetPublicDirectoryExecute");
804 
805     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
806     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
807 
808     vector<string> selectionArgs;
809     vector<string> columns;
810     DataSharePredicates predicates;
811     selectionArgs.push_back(to_string(context->dirType));
812     predicates.SetWhereClause(DIRECTORY_DB_DIRECTORY_TYPE + " = ?");
813     predicates.SetWhereArgs(selectionArgs);
814     string queryUri = MEDIALIBRARY_DIRECTORY_URI;
815     Uri uri(queryUri);
816     int errCode = 0;
817     shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
818     if (resultSet != nullptr) {
819         auto count = 0;
820         auto ret = resultSet->GetRowCount(count);
821         if (ret != NativeRdb::E_OK) {
822             NAPI_ERR_LOG("get rdbstore failed");
823             context->error = JS_INNER_FAIL;
824             return;
825         }
826         if (count == 0) {
827             NAPI_ERR_LOG("Query for get publicDirectory form db failed");
828             context->error = JS_INNER_FAIL;
829             return;
830         }
831         NAPI_INFO_LOG("Query for get publicDirectory count = %{private}d", count);
832         if (resultSet->GoToFirstRow() == NativeRdb::E_OK) {
833             context->directoryRelativePath = get<string>(
834                 ResultSetUtils::GetValFromColumn(DIRECTORY_DB_DIRECTORY, resultSet, TYPE_STRING));
835         }
836         return;
837     } else {
838         context->SaveError(errCode);
839         NAPI_ERR_LOG("Query for get publicDirectory failed! errorCode is = %{public}d", errCode);
840     }
841 }
842 
GetPublicDirectoryCallbackComplete(napi_env env,napi_status status,void * data)843 static void GetPublicDirectoryCallbackComplete(napi_env env, napi_status status, void *data)
844 {
845     MediaLibraryTracer tracer;
846     tracer.Start("GetPublicDirectoryCallbackComplete");
847 
848     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
849     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
850     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
851     jsContext->status = false;
852     if (context->error == ERR_DEFAULT) {
853         napi_create_string_utf8(env, context->directoryRelativePath.c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
854         jsContext->status = true;
855         napi_get_undefined(env, &jsContext->error);
856     } else {
857         context->HandleError(env, jsContext->error);
858         napi_get_undefined(env, &jsContext->data);
859     }
860 
861     tracer.Finish();
862     if (context->work != nullptr) {
863         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
864                                                    context->work, *jsContext);
865     }
866 
867     delete context;
868 }
869 
JSGetPublicDirectory(napi_env env,napi_callback_info info)870 napi_value MediaLibraryNapi::JSGetPublicDirectory(napi_env env, napi_callback_info info)
871 {
872     napi_status status;
873     napi_value result = nullptr;
874     size_t argc = ARGS_TWO;
875     napi_value argv[ARGS_TWO] = {0};
876     napi_value thisVar = nullptr;
877     const int32_t refCount = 1;
878 
879     MediaLibraryTracer tracer;
880     tracer.Start("JSGetPublicDirectory");
881 
882     GET_JS_ARGS(env, info, argc, argv, thisVar);
883     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
884     napi_get_undefined(env, &result);
885 
886     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
887     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
888     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
889         for (size_t i = PARAM0; i < argc; i++) {
890             napi_valuetype valueType = napi_undefined;
891             napi_typeof(env, argv[i], &valueType);
892 
893             if (i == PARAM0 && valueType == napi_number) {
894                 napi_get_value_uint32(env, argv[i], &asyncContext->dirType);
895             } else if (i == PARAM1 && valueType == napi_function) {
896                 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
897                 break;
898             } else {
899                 NAPI_ASSERT(env, false, "type mismatch");
900             }
901         }
902         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPublicDirectory",
903             GetPublicDirectoryExecute, GetPublicDirectoryCallbackComplete);
904     }
905 
906     return result;
907 }
908 
909 #ifdef MEDIALIBRARY_COMPATIBILITY
GetVirtualIdFromApi10Uri(const string & uri)910 static string GetVirtualIdFromApi10Uri(const string &uri)
911 {
912     string fileId = MediaLibraryDataManagerUtils::GetIdFromUri(uri);
913     if (!all_of(fileId.begin(), fileId.end(), ::isdigit)) {
914         return fileId;
915     }
916     int32_t id = stoi(fileId);
917     if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) != string::npos) {
918         return to_string(MediaFileUtils::GetVirtualIdByType(id, MediaType::MEDIA_TYPE_IMAGE));
919     } else if (uri.find(AudioColumn::AUDIO_URI_PREFIX) != string::npos) {
920         return to_string(MediaFileUtils::GetVirtualIdByType(id, MediaType::MEDIA_TYPE_AUDIO));
921     } else {
922         return fileId;
923     }
924 }
925 #endif
926 
GetFileAssetUpdateSelections(MediaLibraryAsyncContext * context)927 static void GetFileAssetUpdateSelections(MediaLibraryAsyncContext *context)
928 {
929     if (!context->uri.empty()) {
930         NAPI_ERR_LOG("context->uri is = %{public}s", context->uri.c_str());
931         context->networkId = MediaLibraryDataManagerUtils::GetNetworkIdFromUri(context->uri);
932 #ifdef MEDIALIBRARY_COMPATIBILITY
933         string fileId = GetVirtualIdFromApi10Uri(context->uri);
934 #else
935         string fileId = MediaLibraryDataManagerUtils::GetIdFromUri(context->uri);
936 #endif
937         if (!fileId.empty()) {
938             string idPrefix = MEDIA_DATA_DB_ID + " = ? ";
939 #ifdef MEDIALIBRARY_COMPATIBILITY
940             context->selection = idPrefix;
941             context->selectionArgs.clear();
942             context->selectionArgs.emplace_back(fileId);
943 #else
944             MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, idPrefix);
945             context->selectionArgs.emplace_back(fileId);
946 #endif
947         }
948     }
949 
950 #ifdef MEDIALIBRARY_COMPATIBILITY
951     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, MediaColumn::ASSETS_QUERY_FILTER);
952 #else
953     string trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? ";
954     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
955     context->selectionArgs.emplace_back("0");
956 #endif
957     string prefix = MEDIA_DATA_DB_MEDIA_TYPE + " <> ? ";
958     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, prefix);
959     context->selectionArgs.emplace_back(to_string(MEDIA_TYPE_ALBUM));
960 }
961 
GetFileAssetsExecute(napi_env env,void * data)962 static void GetFileAssetsExecute(napi_env env, void *data)
963 {
964     MediaLibraryTracer tracer;
965     tracer.Start("GetFileAssetsExecute");
966 
967     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
968     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
969 
970     GetFileAssetUpdateSelections(context);
971     context->fetchColumn = FILE_ASSET_COLUMNS;
972     if (context->extendArgs.find(DATE_FUNCTION) != string::npos) {
973         string group(" GROUP BY (");
974         group += context->extendArgs + " )";
975         context->selection += group;
976         context->fetchColumn.insert(context->fetchColumn.begin(), "count(*)");
977     }
978 
979     context->predicates.SetWhereClause(context->selection);
980     context->predicates.SetWhereArgs(context->selectionArgs);
981     context->predicates.SetOrder(context->order);
982 
983     string queryUri = MEDIALIBRARY_DATA_URI;
984     if (!context->networkId.empty()) {
985         queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
986     }
987     Uri uri(queryUri);
988     int errCode = 0;
989     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
990         context->predicates, context->fetchColumn, errCode);
991     if (resultSet != nullptr) {
992         // Create FetchResult object using the contents of resultSet
993         context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
994         context->fetchFileResult->SetNetworkId(context->networkId);
995         return;
996     } else {
997         context->SaveError(errCode);
998         NAPI_ERR_LOG("Query for get publicDirectory failed! errorCode is = %{public}d", errCode);
999     }
1000 }
1001 
GetNapiFileResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1002 static void GetNapiFileResult(napi_env env, MediaLibraryAsyncContext *context,
1003     unique_ptr<JSAsyncContextOutput> &jsContext)
1004 {
1005     // Create FetchResult object using the contents of resultSet
1006     if (context->fetchFileResult == nullptr) {
1007         NAPI_ERR_LOG("No fetch file result found!");
1008         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1009             "Failed to obtain Fetch File Result");
1010         return;
1011     }
1012     napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchFileResult));
1013     if (fileResult == nullptr) {
1014         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1015             "Failed to create js object for Fetch File Result");
1016     } else {
1017         jsContext->data = fileResult;
1018         jsContext->status = true;
1019         napi_get_undefined(env, &jsContext->error);
1020     }
1021 }
1022 
GetFileAssetsAsyncCallbackComplete(napi_env env,napi_status status,void * data)1023 static void GetFileAssetsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
1024 {
1025     MediaLibraryTracer tracer;
1026     tracer.Start("GetFileAssetsAsyncCallbackComplete");
1027 
1028     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1029     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1030 
1031     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1032     jsContext->status = false;
1033     napi_get_undefined(env, &jsContext->data);
1034 
1035     if (context->error != ERR_DEFAULT) {
1036         context->HandleError(env, jsContext->error);
1037     } else {
1038         GetNapiFileResult(env, context, jsContext);
1039     }
1040 
1041     tracer.Finish();
1042     if (context->work != nullptr) {
1043         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1044                                                    context->work, *jsContext);
1045     }
1046     delete context;
1047 }
1048 
JSGetFileAssets(napi_env env,napi_callback_info info)1049 napi_value MediaLibraryNapi::JSGetFileAssets(napi_env env, napi_callback_info info)
1050 {
1051     napi_status status;
1052     napi_value result = nullptr;
1053     size_t argc = ARGS_TWO;
1054     napi_value argv[ARGS_TWO] = {0};
1055     napi_value thisVar = nullptr;
1056 
1057     MediaLibraryTracer tracer;
1058     tracer.Start("JSGetFileAssets");
1059 
1060     GET_JS_ARGS(env, info, argc, argv, thisVar);
1061     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1062     napi_get_undefined(env, &result);
1063 
1064     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1065     asyncContext->mediaTypes.clear();
1066     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
1067     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1068     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1069         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
1070         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1071 
1072         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetFileAssets", GetFileAssetsExecute,
1073             GetFileAssetsAsyncCallbackComplete);
1074     }
1075 
1076     return result;
1077 }
1078 
1079 #ifdef MEDIALIBRARY_COMPATIBILITY
CompatSetAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<AlbumAsset> & album)1080 static void CompatSetAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<AlbumAsset> &album)
1081 {
1082     MediaLibraryTracer tracer;
1083     tracer.Start("CompatSetAlbumCoverUri");
1084     DataSharePredicates predicates;
1085     int err;
1086     if (album->GetAlbumType() == PhotoAlbumType::USER) {
1087         err = MediaLibraryNapiUtils::GetUserAlbumPredicates(album->GetAlbumId(), predicates);
1088     } else {
1089         err = MediaLibraryNapiUtils::GetSystemAlbumPredicates(album->GetAlbumSubType(), predicates);
1090     }
1091     if (err < 0) {
1092         NAPI_WARN_LOG("Failed to set cover uri for album subtype: %{public}d", album->GetAlbumSubType());
1093         return;
1094     }
1095     predicates.OrderByDesc(MediaColumn::MEDIA_DATE_ADDED);
1096     predicates.Limit(1, 0);
1097 
1098     Uri uri(URI_QUERY_PHOTO_MAP);
1099     vector<string> columns;
1100     columns.assign(MediaColumn::DEFAULT_FETCH_COLUMNS.begin(), MediaColumn::DEFAULT_FETCH_COLUMNS.end());
1101     auto resultSet = UserFileClient::Query(uri, predicates, columns, err);
1102     if (resultSet == nullptr) {
1103         NAPI_ERR_LOG("Query for Album uri failed! errorCode is = %{public}d", err);
1104         context->SaveError(err);
1105         return;
1106     }
1107     auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1108     if (fetchResult->GetCount() == 0) {
1109         return;
1110     }
1111     auto fileAsset = fetchResult->GetFirstObject();
1112     if (fileAsset == nullptr) {
1113         NAPI_WARN_LOG("Failed to get cover asset!");
1114         return;
1115     }
1116     album->SetCoverUri(fileAsset->GetUri());
1117 }
1118 
SetCompatAlbumName(AlbumAsset * albumData)1119 static void SetCompatAlbumName(AlbumAsset *albumData)
1120 {
1121     string albumName;
1122     switch (albumData->GetAlbumSubType()) {
1123         case PhotoAlbumSubType::CAMERA:
1124             albumName = CAMERA_ALBUM_NAME;
1125             break;
1126         case PhotoAlbumSubType::SCREENSHOT:
1127             albumName = SCREEN_SHOT_ALBUM_NAME;
1128             break;
1129         default:
1130             NAPI_WARN_LOG("Ignore unsupported compat album type: %{public}d", albumData->GetAlbumSubType());
1131     }
1132     albumData->SetAlbumName(albumName);
1133 }
1134 
CompatSetAlbumCount(unique_ptr<AlbumAsset> & album)1135 static void CompatSetAlbumCount(unique_ptr<AlbumAsset> &album)
1136 {
1137     MediaLibraryTracer tracer;
1138     tracer.Start("CompatSetAlbumCount");
1139     DataSharePredicates predicates;
1140     int err;
1141     if (album->GetAlbumType() == PhotoAlbumType::USER) {
1142         err = MediaLibraryNapiUtils::GetUserAlbumPredicates(album->GetAlbumId(), predicates);
1143     } else {
1144         err = MediaLibraryNapiUtils::GetSystemAlbumPredicates(album->GetAlbumSubType(), predicates);
1145     }
1146     if (err < 0) {
1147         NAPI_WARN_LOG("Failed to set count for album subtype: %{public}d", album->GetAlbumSubType());
1148         album->SetCount(0);
1149         return;
1150     }
1151 
1152     Uri uri(URI_QUERY_PHOTO_MAP);
1153     vector<string> columns;
1154     auto resultSet = UserFileClient::Query(uri, predicates, columns, err);
1155     if (resultSet == nullptr) {
1156         NAPI_WARN_LOG("Query for assets failed! errorCode is = %{public}d", err);
1157         album->SetCount(0);
1158         return;
1159     }
1160     auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1161     int32_t count = fetchResult->GetCount();
1162     album->SetCount(count);
1163 }
1164 #else
SetAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<AlbumAsset> & album)1165 static void SetAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<AlbumAsset> &album)
1166 {
1167     MediaLibraryTracer tracer;
1168     tracer.Start("SetAlbumCoverUri");
1169     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1170     DataShare::DataSharePredicates predicates;
1171     predicates.SetWhereClause(MEDIA_DATA_DB_BUCKET_ID + " = ? ");
1172     predicates.SetWhereArgs({ to_string(album->GetAlbumId()) });
1173     predicates.SetOrder(MEDIA_DATA_DB_DATE_ADDED + " DESC LIMIT 0,1 ");
1174     vector<string> columns;
1175     string queryUri = MEDIALIBRARY_DATA_URI;
1176     if (!context->networkId.empty()) {
1177         queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
1178         NAPI_DEBUG_LOG("querycoverUri is = %{public}s", queryUri.c_str());
1179     }
1180     Uri uri(queryUri);
1181     int errCode = 0;
1182     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
1183         uri, predicates, columns, errCode);
1184     if (resultSet == nullptr) {
1185         NAPI_ERR_LOG("Query for Album uri failed! errorCode is = %{public}d", errCode);
1186         return;
1187     }
1188     unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1189     fetchFileResult->SetNetworkId(context->networkId);
1190     unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
1191     CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetAlbumCoverUr:FileAsset is nullptr");
1192     string coverUri = fileAsset->GetUri();
1193     album->SetCoverUri(coverUri);
1194     NAPI_DEBUG_LOG("coverUri is = %{public}s", album->GetCoverUri().c_str());
1195 }
1196 #endif
1197 
SetAlbumData(AlbumAsset * albumData,shared_ptr<DataShare::DataShareResultSet> resultSet,const string & networkId)1198 void SetAlbumData(AlbumAsset* albumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
1199     const string &networkId)
1200 {
1201 #ifdef MEDIALIBRARY_COMPATIBILITY
1202     albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_ID, resultSet,
1203         TYPE_INT32)));
1204     albumData->SetAlbumType(static_cast<PhotoAlbumType>(
1205         get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_TYPE, resultSet, TYPE_INT32))));
1206     albumData->SetAlbumSubType(static_cast<PhotoAlbumSubType>(
1207         get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_SUBTYPE, resultSet, TYPE_INT32))));
1208     SetCompatAlbumName(albumData);
1209 #else
1210     // Get album id index and value
1211     albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_BUCKET_ID, resultSet,
1212         TYPE_INT32)));
1213 
1214     // Get album title index and value
1215     albumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_TITLE, resultSet,
1216         TYPE_STRING)));
1217 #endif
1218 
1219     // Get album asset count index and value
1220     albumData->SetCount(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_COUNT, resultSet, TYPE_INT32)));
1221     MediaFileUri fileUri(MEDIA_TYPE_ALBUM, to_string(albumData->GetAlbumId()), networkId,
1222         MEDIA_API_VERSION_DEFAULT);
1223     albumData->SetAlbumUri(fileUri.ToString());
1224     // Get album relativePath index and value
1225     albumData->SetAlbumRelativePath(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_RELATIVE_PATH,
1226         resultSet, TYPE_STRING)));
1227     albumData->SetAlbumDateModified(get<int64_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_DATE_MODIFIED,
1228         resultSet, TYPE_INT64)));
1229 }
1230 
GetAlbumResult(MediaLibraryAsyncContext * context,shared_ptr<DataShareResultSet> resultSet)1231 static void GetAlbumResult(MediaLibraryAsyncContext *context, shared_ptr<DataShareResultSet> resultSet)
1232 {
1233     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1234         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1235         context->fetchAlbumResult = make_unique<FetchResult<AlbumAsset>>(move(resultSet));
1236         context->fetchAlbumResult->SetNetworkId(context->networkId);
1237         context->fetchAlbumResult->SetResultNapiType(context->resultNapiType);
1238         return;
1239     }
1240 
1241     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1242         unique_ptr<AlbumAsset> albumData = make_unique<AlbumAsset>();
1243         if (albumData != nullptr) {
1244             SetAlbumData(albumData.get(), resultSet, context->networkId);
1245 #ifdef MEDIALIBRARY_COMPATIBILITY
1246             CompatSetAlbumCoverUri(context, albumData);
1247             CompatSetAlbumCount(albumData);
1248 #else
1249             SetAlbumCoverUri(context, albumData);
1250 #endif
1251             context->albumNativeArray.push_back(move(albumData));
1252         } else {
1253             context->SaveError(E_NO_MEMORY);
1254         }
1255     }
1256 }
1257 
1258 #ifdef MEDIALIBRARY_COMPATIBILITY
ReplaceAlbumName(const string & arg,string & argInstead)1259 static void ReplaceAlbumName(const string &arg, string &argInstead)
1260 {
1261     if (arg == CAMERA_ALBUM_NAME) {
1262         argInstead = to_string(PhotoAlbumSubType::CAMERA);
1263     } else if (arg == SCREEN_SHOT_ALBUM_NAME) {
1264         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1265     } else if (arg == SCREEN_RECORD_ALBUM_NAME) {
1266         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1267     } else {
1268         argInstead = arg;
1269     }
1270 }
1271 
ReplaceRelativePath(const string & arg,string & argInstead)1272 static bool ReplaceRelativePath(const string &arg, string &argInstead)
1273 {
1274     if (arg == CAMERA_PATH) {
1275         argInstead = to_string(PhotoAlbumSubType::CAMERA);
1276     } else if (arg == SCREEN_SHOT_PATH) {
1277         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1278     } else if (arg == SCREEN_RECORD_PATH) {
1279         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1280     } else if (arg.empty()) {
1281         argInstead = arg;
1282         return false;
1283     } else {
1284         argInstead = arg;
1285     }
1286     return true;
1287 }
1288 
ReplaceSelection(string & selection,vector<string> & selectionArgs,const string & key,const string & keyInstead)1289 static void ReplaceSelection(string &selection, vector<string> &selectionArgs,
1290     const string &key, const string &keyInstead)
1291 {
1292     for (size_t pos = 0; pos != string::npos;) {
1293         pos = selection.find(key, pos);
1294         if (pos == string::npos) {
1295             break;
1296         }
1297 
1298         size_t argPos = selection.find('?', pos);
1299         if (argPos == string::npos) {
1300             break;
1301         }
1302         size_t argIndex = 0;
1303         for (size_t i = 0; i < argPos; i++) {
1304             if (selection[i] == '?') {
1305                 argIndex++;
1306             }
1307         }
1308         if (argIndex > selectionArgs.size() - 1) {
1309             NAPI_WARN_LOG("SelectionArgs size is not valid, selection format maybe incorrect: %{private}s",
1310                 selection.c_str());
1311             break;
1312         }
1313         const string &arg = selectionArgs[argIndex];
1314         string argInstead = arg;
1315         if (key == MEDIA_DATA_DB_RELATIVE_PATH) {
1316             bool shouldReplace = true;
1317             shouldReplace = ReplaceRelativePath(arg, argInstead);
1318             if (shouldReplace) {
1319                 selection.replace(pos, key.length(), keyInstead);
1320             }
1321         } else if (key == MEDIA_DATA_DB_BUCKET_NAME) {
1322             ReplaceAlbumName(arg, argInstead);
1323             selection.replace(pos, key.length(), keyInstead);
1324         } else if (key == MEDIA_DATA_DB_BUCKET_ID) {
1325             selection.replace(pos, key.length(), keyInstead);
1326         }
1327         selectionArgs[argIndex] = argInstead;
1328         argPos = selection.find('?', pos);
1329         if (argPos == string::npos) {
1330             break;
1331         }
1332         pos = argPos + 1;
1333     }
1334 }
1335 
UpdateCompatSelection(MediaLibraryAsyncContext * context)1336 static void UpdateCompatSelection(MediaLibraryAsyncContext *context)
1337 {
1338     ReplaceSelection(context->selection, context->selectionArgs, MEDIA_DATA_DB_BUCKET_ID, PhotoAlbumColumns::ALBUM_ID);
1339     ReplaceSelection(context->selection, context->selectionArgs,
1340         MEDIA_DATA_DB_BUCKET_NAME, PhotoAlbumColumns::ALBUM_SUBTYPE);
1341     ReplaceSelection(context->selection, context->selectionArgs,
1342         MEDIA_DATA_DB_RELATIVE_PATH, PhotoAlbumColumns::ALBUM_SUBTYPE);
1343     static const string COMPAT_QUERY_FILTER = PhotoAlbumColumns::ALBUM_SUBTYPE + " IN (" +
1344         to_string(PhotoAlbumSubType::SCREENSHOT) + "," +
1345         to_string(PhotoAlbumSubType::CAMERA) + ")";
1346     if (!context->selection.empty()) {
1347         context->selection = COMPAT_QUERY_FILTER + " AND " + context->selection;
1348     } else {
1349         context->selection = COMPAT_QUERY_FILTER;
1350     }
1351 }
1352 #endif
1353 
GetResultDataExecute(napi_env env,void * data)1354 static void GetResultDataExecute(napi_env env, void *data)
1355 {
1356     MediaLibraryTracer tracer;
1357     tracer.Start("GetResultDataExecute");
1358 
1359     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1360 
1361 #ifdef MEDIALIBRARY_COMPATIBILITY
1362     UpdateCompatSelection(context);
1363 #else
1364     MediaLibraryNapiUtils::UpdateMediaTypeSelections(context);
1365 #endif
1366     context->predicates.SetWhereClause(context->selection);
1367     context->predicates.SetWhereArgs(context->selectionArgs);
1368     if (!context->order.empty()) {
1369         context->predicates.SetOrder(context->order);
1370     }
1371 
1372 #ifdef MEDIALIBRARY_COMPATIBILITY
1373     vector<string> columns;
1374     const set<string> &defaultFetchCols = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
1375     columns.assign(defaultFetchCols.begin(), defaultFetchCols.end());
1376     columns.push_back(PhotoAlbumColumns::ALBUM_DATE_MODIFIED);
1377 #else
1378     vector<string> columns;
1379 #endif
1380     string queryUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
1381     if (!context->networkId.empty()) {
1382         queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId +
1383             MEDIALIBRARY_DATA_URI_IDENTIFIER + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
1384         NAPI_DEBUG_LOG("queryAlbumUri is = %{public}s", queryUri.c_str());
1385     }
1386     Uri uri(queryUri);
1387     int errCode = 0;
1388     shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, context->predicates, columns, errCode);
1389 
1390     if (resultSet == nullptr) {
1391         NAPI_ERR_LOG("GetMediaResultData resultSet is nullptr, errCode is %{public}d", errCode);
1392         context->SaveError(errCode);
1393         return;
1394     }
1395 
1396     GetAlbumResult(context, resultSet);
1397 }
1398 
MediaLibAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1399 static void MediaLibAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1400     unique_ptr<JSAsyncContextOutput> &jsContext)
1401 {
1402     if (context->albumNativeArray.empty()) {
1403         napi_value albumNoArray = nullptr;
1404         napi_create_array(env, &albumNoArray);
1405         jsContext->status = true;
1406         napi_get_undefined(env, &jsContext->error);
1407         jsContext->data = albumNoArray;
1408     } else {
1409         napi_value albumArray = nullptr;
1410         napi_create_array_with_length(env, context->albumNativeArray.size(), &albumArray);
1411         for (size_t i = 0; i < context->albumNativeArray.size(); i++) {
1412             napi_value albumNapiObj = AlbumNapi::CreateAlbumNapi(env, context->albumNativeArray[i]);
1413             napi_set_element(env, albumArray, i, albumNapiObj);
1414         }
1415         jsContext->status = true;
1416         napi_get_undefined(env, &jsContext->error);
1417         jsContext->data = albumArray;
1418     }
1419 }
1420 
UserFileMgrAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1421 static void UserFileMgrAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1422     unique_ptr<JSAsyncContextOutput> &jsContext)
1423 {
1424     if (context->fetchAlbumResult->GetCount() < 0) {
1425         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1426             "find no data by options");
1427     } else {
1428         napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchAlbumResult));
1429         if (fileResult == nullptr) {
1430             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1431                 "Failed to create js object for Fetch Album Result");
1432         } else {
1433             jsContext->data = fileResult;
1434             jsContext->status = true;
1435             napi_get_undefined(env, &jsContext->error);
1436         }
1437     }
1438 }
1439 
AlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1440 static void AlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1441     unique_ptr<JSAsyncContextOutput> &jsContext)
1442 {
1443     if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
1444         MediaLibAlbumsAsyncResult(env, context, jsContext);
1445     } else {
1446         UserFileMgrAlbumsAsyncResult(env, context, jsContext);
1447     }
1448 }
1449 
AlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)1450 static void AlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
1451 {
1452     MediaLibraryTracer tracer;
1453     tracer.Start("AlbumsAsyncCallbackComplete");
1454 
1455     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1456     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1457     jsContext->status = false;
1458     napi_get_undefined(env, &jsContext->error);
1459     if (context->error != ERR_DEFAULT) {
1460         napi_get_undefined(env, &jsContext->data);
1461         context->HandleError(env, jsContext->error);
1462     } else {
1463         AlbumsAsyncResult(env, context, jsContext);
1464     }
1465 
1466     tracer.Finish();
1467     if (context->work != nullptr) {
1468         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1469                                                    context->work, *jsContext);
1470     }
1471     delete context;
1472 }
1473 
JSGetAlbums(napi_env env,napi_callback_info info)1474 napi_value MediaLibraryNapi::JSGetAlbums(napi_env env, napi_callback_info info)
1475 {
1476     napi_status status;
1477     napi_value result = nullptr;
1478     size_t argc = ARGS_TWO;
1479     napi_value argv[ARGS_TWO] = {0};
1480     napi_value thisVar = nullptr;
1481 
1482     MediaLibraryTracer tracer;
1483     tracer.Start("JSGetAlbums");
1484 
1485     GET_JS_ARGS(env, info, argc, argv, thisVar);
1486     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1487     napi_get_undefined(env, &result);
1488 
1489     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1490     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1491     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1492         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
1493         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1494 
1495         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetAlbums", GetResultDataExecute,
1496             AlbumsAsyncCallbackComplete);
1497     }
1498 
1499     return result;
1500 }
1501 
1502 #ifndef MEDIALIBRARY_COMPATIBILITY
getFileAssetById(int32_t id,const string & networkId,MediaLibraryAsyncContext * context)1503 static void getFileAssetById(int32_t id, const string &networkId, MediaLibraryAsyncContext *context)
1504 {
1505     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1506     vector<string> columns;
1507     DataShare::DataSharePredicates predicates;
1508 
1509     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
1510     predicates.SetWhereArgs({ to_string(id) });
1511 
1512     string queryUri = MEDIALIBRARY_DATA_URI;
1513     Uri uri(queryUri);
1514     int errCode = 0;
1515 
1516     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
1517     CHECK_NULL_PTR_RETURN_VOID(resultSet, "Failed to get file asset by id, query resultSet is nullptr");
1518 
1519     // Create FetchResult object using the contents of resultSet
1520     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1521     CHECK_NULL_PTR_RETURN_VOID(context->fetchFileResult, "Failed to get file asset by id, fetchFileResult is nullptr");
1522     context->fetchFileResult->SetNetworkId(networkId);
1523     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1524         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1525         context->fetchFileResult->SetResultNapiType(context->resultNapiType);
1526     }
1527     if (context->fetchFileResult->GetCount() < 1) {
1528         NAPI_ERR_LOG("Failed to query file by id: %{public}d, query count is 0", id);
1529         return;
1530     }
1531     unique_ptr<FileAsset> fileAsset = context->fetchFileResult->GetFirstObject();
1532     CHECK_NULL_PTR_RETURN_VOID(fileAsset, "getFileAssetById: fileAsset is nullptr");
1533     context->fileAsset = move(fileAsset);
1534 }
1535 #endif
1536 
1537 #ifdef MEDIALIBRARY_COMPATIBILITY
SetFileAssetByIdV9(int32_t id,const string & networkId,MediaLibraryAsyncContext * context)1538 static void SetFileAssetByIdV9(int32_t id, const string &networkId, MediaLibraryAsyncContext *context)
1539 {
1540     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1541     bool isValid = false;
1542     string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1543     if (!isValid) {
1544         NAPI_ERR_LOG("get title is invalid");
1545         return;
1546     }
1547     string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1548     if (!isValid) {
1549         NAPI_ERR_LOG("get relativePath is invalid");
1550         return;
1551     }
1552     unique_ptr<FileAsset> fileAsset = make_unique<FileAsset>();
1553     fileAsset->SetId(id);
1554     MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1555     string uri;
1556     if (MediaFileUtils::StartsWith(relativePath, DOC_DIR_VALUES) ||
1557         MediaFileUtils::StartsWith(relativePath, DOWNLOAD_DIR_VALUES)) {
1558         uri = MediaFileUtils::GetVirtualUriFromRealUri(MediaFileUri(MediaType::MEDIA_TYPE_FILE,
1559             to_string(id), networkId, MEDIA_API_VERSION_V9).ToString());
1560     } else {
1561         uri = MediaFileUtils::GetVirtualUriFromRealUri(MediaFileUri(mediaType,
1562             to_string(id), networkId, MEDIA_API_VERSION_V9).ToString());
1563     }
1564     fileAsset->SetUri(uri);
1565     fileAsset->SetMediaType(mediaType);
1566     fileAsset->SetDisplayName(displayName);
1567     fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1568     fileAsset->SetResultNapiType(ResultNapiType::TYPE_MEDIALIBRARY);
1569     fileAsset->SetRelativePath(relativePath);
1570     context->fileAsset = move(fileAsset);
1571 }
1572 #endif
1573 
SetFileAssetByIdV10(int32_t id,const string & networkId,const string & uri,MediaLibraryAsyncContext * context)1574 static void SetFileAssetByIdV10(int32_t id, const string &networkId, const string &uri,
1575                                 MediaLibraryAsyncContext *context)
1576 {
1577     bool isValid = false;
1578     string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1579     if (!isValid) {
1580         NAPI_ERR_LOG("getting title is invalid");
1581         return;
1582     }
1583     unique_ptr<FileAsset> fileAsset = make_unique<FileAsset>();
1584     fileAsset->SetId(id);
1585     MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1586     fileAsset->SetUri(uri);
1587     fileAsset->SetMediaType(mediaType);
1588     fileAsset->SetDisplayName(displayName);
1589     fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1590     fileAsset->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
1591     fileAsset->SetTimePending(UNCREATE_FILE_TIMEPENDING);
1592     context->fileAsset = move(fileAsset);
1593 }
1594 
PhotoAccessSetFileAssetByIdV10(int32_t id,const string & networkId,const string & uri,MediaLibraryAsyncContext * context)1595 static void PhotoAccessSetFileAssetByIdV10(int32_t id, const string &networkId, const string &uri,
1596                                            MediaLibraryAsyncContext *context)
1597 {
1598     bool isValid = false;
1599     string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1600     if (!isValid) {
1601         NAPI_ERR_LOG("getting title is invalid");
1602         return;
1603     }
1604     auto fileAsset = make_unique<FileAsset>();
1605     fileAsset->SetId(id);
1606     MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1607     fileAsset->SetUri(uri);
1608     fileAsset->SetMediaType(mediaType);
1609     fileAsset->SetDisplayName(displayName);
1610     fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1611     fileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
1612     fileAsset->SetTimePending(UNCREATE_FILE_TIMEPENDING);
1613     context->fileAsset = move(fileAsset);
1614 }
1615 
JSCreateUriInCallback(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1616 static void JSCreateUriInCallback(napi_env env, MediaLibraryAsyncContext *context,
1617     unique_ptr<JSAsyncContextOutput> &jsContext)
1618 {
1619     napi_value jsObject = nullptr;
1620     if (context->uri.empty()) {
1621         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1622             "Obtain file asset uri failed");
1623         napi_get_undefined(env, &jsContext->data);
1624     } else {
1625         napi_status status = napi_create_string_utf8(env, context->uri.c_str(), NAPI_AUTO_LENGTH, &jsObject);
1626         if (status != napi_ok || jsObject == nullptr) {
1627             NAPI_ERR_LOG("Failed to get file asset uri napi object");
1628             napi_get_undefined(env, &jsContext->data);
1629             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1630                 "Failed to create js object for FileAsset");
1631         } else {
1632             jsContext->data = jsObject;
1633             napi_get_undefined(env, &jsContext->error);
1634             jsContext->status = true;
1635         }
1636     }
1637 }
1638 
JSCreateAssetInCallback(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1639 static void JSCreateAssetInCallback(napi_env env, MediaLibraryAsyncContext *context,
1640     unique_ptr<JSAsyncContextOutput> &jsContext)
1641 {
1642     napi_value jsFileAsset = nullptr;
1643     if (context->fileAsset == nullptr) {
1644         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1645             "Obtain file asset failed");
1646         napi_get_undefined(env, &jsContext->data);
1647     } else {
1648         jsFileAsset = FileAssetNapi::CreateFileAsset(env, context->fileAsset);
1649         if (jsFileAsset == nullptr) {
1650             NAPI_ERR_LOG("Failed to get file asset napi object");
1651             napi_get_undefined(env, &jsContext->data);
1652             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1653                 "Failed to create js object for FileAsset");
1654         } else {
1655             NAPI_DEBUG_LOG("JSCreateAssetCompleteCallback jsFileAsset != nullptr");
1656             jsContext->data = jsFileAsset;
1657             napi_get_undefined(env, &jsContext->error);
1658             jsContext->status = true;
1659         }
1660     }
1661 }
1662 
JSCreateAssetCompleteCallback(napi_env env,napi_status status,void * data)1663 static void JSCreateAssetCompleteCallback(napi_env env, napi_status status, void *data)
1664 {
1665     MediaLibraryTracer tracer;
1666     tracer.Start("JSCreateAssetCompleteCallback");
1667 
1668     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
1669     auto jsContext = make_unique<JSAsyncContextOutput>();
1670     jsContext->status = false;
1671 
1672     if (context->error == ERR_DEFAULT) {
1673         if (context->isCreateByComponent) {
1674             JSCreateUriInCallback(env, context, jsContext);
1675         } else {
1676             JSCreateAssetInCallback(env, context, jsContext);
1677         }
1678     } else {
1679         context->HandleError(env, jsContext->error);
1680         napi_get_undefined(env, &jsContext->data);
1681     }
1682 
1683     tracer.Finish();
1684     if (context->work != nullptr) {
1685         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1686                                                    context->work, *jsContext);
1687     }
1688     delete context;
1689 }
1690 
CheckDisplayNameParams(MediaLibraryAsyncContext * context)1691 static bool CheckDisplayNameParams(MediaLibraryAsyncContext *context)
1692 {
1693     if (context == nullptr) {
1694         NAPI_ERR_LOG("Async context is null");
1695         return false;
1696     }
1697     if (!context->isCreateByComponent) {
1698         bool isValid = false;
1699         string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1700         if (!isValid) {
1701             NAPI_ERR_LOG("getting displayName is invalid");
1702             return false;
1703         }
1704         if (displayName.empty()) {
1705             return false;
1706         }
1707     }
1708 
1709     return true;
1710 }
1711 
GetFirstDirName(const string & relativePath)1712 static string GetFirstDirName(const string &relativePath)
1713 {
1714     string firstDirName = "";
1715     if (!relativePath.empty()) {
1716         string::size_type pos = relativePath.find_first_of('/');
1717         if (pos == relativePath.length()) {
1718             return relativePath;
1719         }
1720         firstDirName = relativePath.substr(0, pos + 1);
1721         NAPI_DEBUG_LOG("firstDirName substr = %{private}s", firstDirName.c_str());
1722     }
1723     return firstDirName;
1724 }
1725 
IsDirectory(const string & dirName)1726 static bool IsDirectory(const string &dirName)
1727 {
1728     struct stat statInfo {};
1729     if (stat((ROOT_MEDIA_DIR + dirName).c_str(), &statInfo) == SUCCESS) {
1730         if (statInfo.st_mode & S_IFDIR) {
1731             return true;
1732         }
1733     }
1734 
1735     return false;
1736 }
1737 
CheckTypeOfType(const string & firstDirName,int32_t fileMediaType)1738 static bool CheckTypeOfType(const string &firstDirName, int32_t fileMediaType)
1739 {
1740     // "CDSA/"
1741     if (!strcmp(firstDirName.c_str(), directoryEnumValues[0].c_str())) {
1742         if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
1743             return true;
1744         } else {
1745             return false;
1746         }
1747     }
1748     // "Movies/"
1749     if (!strcmp(firstDirName.c_str(), directoryEnumValues[1].c_str())) {
1750         if (fileMediaType == MEDIA_TYPE_VIDEO) {
1751             return true;
1752         } else {
1753             return false;
1754         }
1755     }
1756     if (!strcmp(firstDirName.c_str(), directoryEnumValues[NUM_2].c_str())) {
1757         if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
1758             return true;
1759         } else {
1760             NAPI_INFO_LOG("CheckTypeOfType RETURN FALSE");
1761             return false;
1762         }
1763     }
1764     if (!strcmp(firstDirName.c_str(), directoryEnumValues[NUM_3].c_str())) {
1765         if (fileMediaType == MEDIA_TYPE_AUDIO) {
1766             return true;
1767         } else {
1768             return false;
1769         }
1770     }
1771     return true;
1772 }
CheckRelativePathParams(MediaLibraryAsyncContext * context)1773 static bool CheckRelativePathParams(MediaLibraryAsyncContext *context)
1774 {
1775     if (context == nullptr) {
1776         NAPI_ERR_LOG("Async context is null");
1777         return false;
1778     }
1779     bool isValid = false;
1780     string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1781     if (!isValid) {
1782         NAPI_DEBUG_LOG("getting relativePath is invalid");
1783         return false;
1784     }
1785     isValid = false;
1786     int32_t fileMediaType = context->valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
1787     if (!isValid) {
1788         NAPI_DEBUG_LOG("getting fileMediaType is invalid");
1789         return false;
1790     }
1791     if (relativePath.empty()) {
1792         return false;
1793     }
1794 
1795     if (IsDirectory(relativePath)) {
1796         return true;
1797     }
1798 
1799     string firstDirName = GetFirstDirName(relativePath);
1800     if (!firstDirName.empty() && IsDirectory(firstDirName)) {
1801         return true;
1802     }
1803 
1804     if (!firstDirName.empty()) {
1805         NAPI_DEBUG_LOG("firstDirName = %{private}s", firstDirName.c_str());
1806         for (unsigned int i = 0; i < directoryEnumValues.size(); i++) {
1807             NAPI_DEBUG_LOG("directoryEnumValues%{public}d = %{public}s", i, directoryEnumValues[i].c_str());
1808             if (!strcmp(firstDirName.c_str(), directoryEnumValues[i].c_str())) {
1809                 return CheckTypeOfType(firstDirName, fileMediaType);
1810             }
1811         }
1812         NAPI_DEBUG_LOG("firstDirName = %{private}s", firstDirName.c_str());
1813     }
1814     return false;
1815 }
1816 
GetJSArgsForCreateAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)1817 napi_value GetJSArgsForCreateAsset(napi_env env, size_t argc, const napi_value argv[],
1818                                    MediaLibraryAsyncContext &asyncContext)
1819 {
1820     const int32_t refCount = 1;
1821     napi_value result = nullptr;
1822     auto context = &asyncContext;
1823     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1824     int32_t fileMediaType = 0;
1825     size_t res = 0;
1826     char relativePathBuffer[PATH_MAX];
1827     char titleBuffer[PATH_MAX];
1828     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1829 
1830     for (size_t i = PARAM0; i < argc; i++) {
1831         napi_valuetype valueType = napi_undefined;
1832         napi_typeof(env, argv[i], &valueType);
1833         if (i == PARAM0 && valueType == napi_number) {
1834             napi_get_value_int32(env, argv[i], &fileMediaType);
1835         } else if (i == PARAM1 && valueType == napi_string) {
1836             napi_get_value_string_utf8(env, argv[i], titleBuffer, PATH_MAX, &res);
1837             NAPI_DEBUG_LOG("displayName = %{private}s", string(titleBuffer).c_str());
1838         } else if (i == PARAM2 && valueType == napi_string) {
1839             napi_get_value_string_utf8(env, argv[i], relativePathBuffer, PATH_MAX, &res);
1840             NAPI_DEBUG_LOG("relativePath = %{private}s", string(relativePathBuffer).c_str());
1841         } else if (i == PARAM3 && valueType == napi_function) {
1842             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1843         } else {
1844             NAPI_DEBUG_LOG("type mismatch, valueType: %{public}d", valueType);
1845             return result;
1846     }
1847     }
1848 
1849     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileMediaType);
1850     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, string(titleBuffer));
1851     context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, string(relativePathBuffer));
1852 
1853     context->assetType = TYPE_DEFAULT;
1854     if (fileMediaType == MediaType::MEDIA_TYPE_IMAGE || fileMediaType == MediaType::MEDIA_TYPE_VIDEO) {
1855         context->assetType = TYPE_PHOTO;
1856     } else if (fileMediaType == MediaType::MEDIA_TYPE_AUDIO) {
1857         context->assetType = TYPE_AUDIO;
1858     }
1859 
1860     NAPI_DEBUG_LOG("GetJSArgsForCreateAsset END");
1861     // Return true napi_value if params are successfully obtained
1862     napi_get_boolean(env, true, &result);
1863     return result;
1864 }
1865 
GetCreateUri(MediaLibraryAsyncContext * context,string & uri)1866 static void GetCreateUri(MediaLibraryAsyncContext *context, string &uri)
1867 {
1868     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1869         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1870         switch (context->assetType) {
1871             case TYPE_PHOTO:
1872                 uri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
1873                     ((context->isCreateByComponent) ? UFM_CREATE_PHOTO_COMPONENT : UFM_CREATE_PHOTO) :
1874                     ((context->isCreateByComponent) ? PAH_CREATE_PHOTO_COMPONENT : PAH_CREATE_PHOTO);
1875                 break;
1876             case TYPE_AUDIO:
1877                 uri = (context->isCreateByComponent) ? UFM_CREATE_AUDIO_COMPONENT : UFM_CREATE_AUDIO;
1878                 break;
1879             default:
1880                 NAPI_ERR_LOG("Unsupported creation napitype %{public}d", static_cast<int32_t>(context->assetType));
1881                 return;
1882         }
1883         MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1884     } else {
1885 #ifdef MEDIALIBRARY_COMPATIBILITY
1886         bool isValid = false;
1887         string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1888         if (MediaFileUtils::StartsWith(relativePath, DOC_DIR_VALUES) ||
1889             MediaFileUtils::StartsWith(relativePath, DOWNLOAD_DIR_VALUES)) {
1890             uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1891             MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
1892             return;
1893         }
1894         switch (context->assetType) {
1895             case TYPE_PHOTO:
1896                 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_PHOTOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1897                 break;
1898             case TYPE_AUDIO:
1899                 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_AUDIOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1900                 break;
1901             case TYPE_DEFAULT:
1902                 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1903                 break;
1904             default:
1905                 NAPI_ERR_LOG("Unsupported creation napi type %{public}d", static_cast<int32_t>(context->assetType));
1906                 return;
1907         }
1908         MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
1909 #else
1910         uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1911 #endif
1912     }
1913 }
1914 
JSCreateAssetExecute(napi_env env,void * data)1915 static void JSCreateAssetExecute(napi_env env, void *data)
1916 {
1917     MediaLibraryTracer tracer;
1918     tracer.Start("JSCreateAssetExecute");
1919 
1920     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
1921     if (!CheckDisplayNameParams(context)) {
1922         context->error = JS_E_DISPLAYNAME;
1923         return;
1924     }
1925     if ((context->resultNapiType != ResultNapiType::TYPE_USERFILE_MGR) && (!CheckRelativePathParams(context))) {
1926         context->error = JS_E_RELATIVEPATH;
1927         return;
1928     }
1929 
1930     string uri;
1931     GetCreateUri(context, uri);
1932     Uri createFileUri(uri);
1933     string outUri;
1934     int index = UserFileClient::InsertExt(createFileUri, context->valuesBucket, outUri);
1935     if (index < 0) {
1936         context->SaveError(index);
1937     } else {
1938         if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
1939             if (context->isCreateByComponent) {
1940                 context->uri = outUri;
1941             } else {
1942                 SetFileAssetByIdV10(index, "", outUri, context);
1943             }
1944         } else {
1945 #ifdef MEDIALIBRARY_COMPATIBILITY
1946             SetFileAssetByIdV9(index, "", context);
1947 #else
1948             getFileAssetById(index, "", context);
1949 #endif
1950         }
1951     }
1952 }
1953 
JSCreateAsset(napi_env env,napi_callback_info info)1954 napi_value MediaLibraryNapi::JSCreateAsset(napi_env env, napi_callback_info info)
1955 {
1956     napi_status status;
1957     napi_value result = nullptr;
1958     size_t argc = ARGS_FOUR;
1959     napi_value argv[ARGS_FOUR] = {0};
1960     napi_value thisVar = nullptr;
1961 
1962     MediaLibraryTracer tracer;
1963     tracer.Start("JSCreateAsset");
1964 
1965     GET_JS_ARGS(env, info, argc, argv, thisVar);
1966     NAPI_ASSERT(env, (argc == ARGS_THREE || argc == ARGS_FOUR), "requires 4 parameters maximum");
1967     napi_get_undefined(env, &result);
1968 
1969     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1970     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
1971     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1972     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1973         result = GetJSArgsForCreateAsset(env, argc, argv, *asyncContext);
1974         ASSERT_NULLPTR_CHECK(env, result);
1975 
1976         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCreateAsset", JSCreateAssetExecute,
1977             JSCreateAssetCompleteCallback);
1978     }
1979 
1980     return result;
1981 }
1982 
1983 #ifdef MEDIALIBRARY_COMPATIBILITY
HandleCompatDeletePhoto(MediaLibraryAsyncContext * context,const string & mediaType,const string & deleteId)1984 static void HandleCompatDeletePhoto(MediaLibraryAsyncContext *context,
1985     const string &mediaType, const string &deleteId)
1986 {
1987     Uri uri(URI_DELETE_PHOTOS);
1988     DataSharePredicates predicates;
1989     predicates.In(MediaColumn::MEDIA_ID, vector<string>({ deleteId }));
1990     predicates.GreaterThan(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
1991     DataShareValuesBucket valuesBucket;
1992     valuesBucket.Put(MediaColumn::MEDIA_ID, deleteId);
1993     int changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
1994     if (changedRows < 0) {
1995         context->SaveError(changedRows);
1996         return;
1997     }
1998     context->retVal = changedRows;
1999 }
2000 
HandleCompatDelete(MediaLibraryAsyncContext * context,const string & mediaType,const string & deleteId)2001 static inline void HandleCompatDelete(MediaLibraryAsyncContext *context,
2002     const string &mediaType, const string &deleteId)
2003 {
2004     if (mediaType == IMAGE_ASSET_TYPE || mediaType == VIDEO_ASSET_TYPE) {
2005         return HandleCompatDeletePhoto(context, mediaType, deleteId);
2006     }
2007     NAPI_WARN_LOG("Ignore unsupported media type deletion: %{public}s", mediaType.c_str());
2008 }
2009 #endif
2010 
JSDeleteAssetExecute(napi_env env,void * data)2011 static void JSDeleteAssetExecute(napi_env env, void *data)
2012 {
2013     MediaLibraryTracer tracer;
2014     tracer.Start("JSDeleteAssetExecute");
2015 
2016     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2017     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2018 
2019     string mediaType, deleteId;
2020     bool isValid = false;
2021     string notifyUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
2022     if (!isValid) {
2023         context->error = ERR_INVALID_OUTPUT;
2024         return;
2025     }
2026 #ifdef MEDIALIBRARY_COMPATIBILITY
2027     notifyUri = MediaFileUtils::GetRealUriFromVirtualUri(notifyUri);
2028 #endif
2029     size_t index = notifyUri.rfind('/');
2030     if (index != string::npos) {
2031         deleteId = notifyUri.substr(index + 1);
2032         notifyUri = notifyUri.substr(0, index);
2033         size_t indexType = notifyUri.rfind('/');
2034         if (indexType != string::npos) {
2035             mediaType = notifyUri.substr(indexType + 1);
2036         }
2037     }
2038     if (MediaFileUtils::IsUriV10(mediaType)) {
2039         NAPI_ERR_LOG("Unsupported media type: %{public}s", mediaType.c_str());
2040         context->SaveError(E_INVALID_URI);
2041         return;
2042     }
2043 #ifdef MEDIALIBRARY_COMPATIBILITY
2044     if (mediaType == IMAGE_ASSET_TYPE || mediaType == VIDEO_ASSET_TYPE || mediaType == AUDIO_ASSET_TYPE) {
2045         return HandleCompatDelete(context, mediaType, deleteId);
2046     }
2047 #endif
2048     notifyUri = MEDIALIBRARY_DATA_URI + "/" + mediaType;
2049     string deleteUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_DELETEASSET;
2050     Uri deleteAssetUri(deleteUri);
2051     DataSharePredicates predicates;
2052     predicates.EqualTo(MEDIA_DATA_DB_ID, deleteId);
2053     int retVal = UserFileClient::Delete(deleteAssetUri, predicates);
2054     if (retVal < 0) {
2055         context->SaveError(retVal);
2056     } else {
2057         context->retVal = retVal;
2058         Uri deleteNotify(notifyUri);
2059         UserFileClient::NotifyChange(deleteNotify);
2060     }
2061 }
2062 
JSDeleteAssetCompleteCallback(napi_env env,napi_status status,void * data)2063 static void JSDeleteAssetCompleteCallback(napi_env env, napi_status status, void *data)
2064 {
2065     MediaLibraryTracer tracer;
2066     tracer.Start("JSDeleteAssetCompleteCallback");
2067 
2068     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2069     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2070     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2071     jsContext->status = false;
2072 
2073     if (context->error == ERR_DEFAULT) {
2074         NAPI_DEBUG_LOG("Delete result = %{public}d", context->retVal);
2075         napi_create_int32(env, context->retVal, &jsContext->data);
2076         napi_get_undefined(env, &jsContext->error);
2077         jsContext->status = true;
2078     } else {
2079         context->HandleError(env, jsContext->error);
2080         napi_get_undefined(env, &jsContext->data);
2081     }
2082 
2083     tracer.Finish();
2084     if (context->work != nullptr) {
2085         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2086                                                    context->work, *jsContext);
2087     }
2088 
2089     delete context;
2090 }
2091 
JSTrashAssetExecute(napi_env env,void * data)2092 static void JSTrashAssetExecute(napi_env env, void *data)
2093 {
2094     MediaLibraryTracer tracer;
2095     tracer.Start("JSTrashAssetExecute");
2096 
2097     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
2098     string uri = context->uri;
2099     if (uri.empty()) {
2100         context->error = ERR_INVALID_OUTPUT;
2101         return;
2102     }
2103     MediaFileUri::RemoveAllFragment(uri);
2104     string trashId = MediaFileUtils::GetIdFromUri(uri);
2105     string trashUri;
2106     if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) != string::npos) {
2107         trashUri = UFM_UPDATE_PHOTO;
2108     } else if (uri.find(AudioColumn::AUDIO_URI_PREFIX) != string::npos) {
2109         trashUri = UFM_UPDATE_AUDIO;
2110     } else {
2111         context->error = E_VIOLATION_PARAMETERS;
2112         return;
2113     }
2114     MediaLibraryNapiUtils::UriAppendKeyValue(trashUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2115     Uri updateAssetUri(trashUri);
2116     DataSharePredicates predicates;
2117     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
2118     predicates.SetWhereArgs({ trashId });
2119     DataShareValuesBucket valuesBucket;
2120     valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, MediaFileUtils::UTCTimeSeconds());
2121     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
2122     if (changedRows < 0) {
2123         context->SaveError(changedRows);
2124         NAPI_ERR_LOG("Media asset delete failed, err: %{public}d", changedRows);
2125     }
2126 }
2127 
JSTrashAssetCompleteCallback(napi_env env,napi_status status,void * data)2128 static void JSTrashAssetCompleteCallback(napi_env env, napi_status status, void *data)
2129 {
2130     MediaLibraryTracer tracer;
2131     tracer.Start("JSTrashAssetCompleteCallback");
2132 
2133     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2134     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2135     jsContext->status = false;
2136     napi_get_undefined(env, &jsContext->data);
2137     if (context->error == ERR_DEFAULT) {
2138         jsContext->status = true;
2139     } else {
2140         context->HandleError(env, jsContext->error);
2141     }
2142     if (context->work != nullptr) {
2143         tracer.Finish();
2144         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2145             context->work, *jsContext);
2146     }
2147 
2148     delete context;
2149 }
2150 
GetJSArgsForDeleteAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)2151 napi_value GetJSArgsForDeleteAsset(napi_env env, size_t argc, const napi_value argv[],
2152                                    MediaLibraryAsyncContext &asyncContext)
2153 {
2154     const int32_t refCount = 1;
2155     napi_value result = nullptr;
2156     auto context = &asyncContext;
2157     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2158     size_t res = 0;
2159     char buffer[PATH_MAX];
2160 
2161     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2162 
2163     for (size_t i = PARAM0; i < argc; i++) {
2164         napi_valuetype valueType = napi_undefined;
2165         napi_typeof(env, argv[i], &valueType);
2166 
2167         if (i == PARAM0 && valueType == napi_string) {
2168             napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
2169         } else if (i == PARAM1 && valueType == napi_function) {
2170             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2171             break;
2172         } else {
2173             NAPI_ASSERT(env, false, "type mismatch");
2174         }
2175     }
2176 
2177     context->valuesBucket.Put(MEDIA_DATA_DB_URI, string(buffer));
2178 
2179     // Return true napi_value if params are successfully obtained
2180     napi_get_boolean(env, true, &result);
2181     return result;
2182 }
2183 
JSDeleteAsset(napi_env env,napi_callback_info info)2184 napi_value MediaLibraryNapi::JSDeleteAsset(napi_env env, napi_callback_info info)
2185 {
2186     napi_status status;
2187     napi_value result = nullptr;
2188     size_t argc = ARGS_TWO;
2189     napi_value argv[ARGS_TWO] = {0};
2190     napi_value thisVar = nullptr;
2191 
2192     MediaLibraryTracer tracer;
2193     tracer.Start("JSDeleteAsset");
2194 
2195     GET_JS_ARGS(env, info, argc, argv, thisVar);
2196     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2197     napi_get_undefined(env, &result);
2198 
2199     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2200     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2201     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2202         result = GetJSArgsForDeleteAsset(env, argc, argv, *asyncContext);
2203         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
2204 
2205         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSDeleteAsset", JSDeleteAssetExecute,
2206             JSDeleteAssetCompleteCallback);
2207     }
2208 
2209     return result;
2210 }
2211 
SetValueInt32(const napi_env & env,const char * fieldStr,const int intValue,napi_value & result)2212 static napi_status SetValueInt32(const napi_env& env, const char* fieldStr, const int intValue, napi_value& result)
2213 {
2214     napi_value value;
2215     napi_status status = napi_create_int32(env, intValue, &value);
2216     if (status != napi_ok) {
2217         NAPI_ERR_LOG("Set value create int32 error! field: %{public}s", fieldStr);
2218         return status;
2219     }
2220     status = napi_set_named_property(env, result, fieldStr, value);
2221     if (status != napi_ok) {
2222         NAPI_ERR_LOG("Set int32 named property error! field: %{public}s", fieldStr);
2223     }
2224     return status;
2225 }
2226 
SetValueArray(const napi_env & env,const char * fieldStr,const std::list<Uri> listValue,napi_value & result)2227 static napi_status SetValueArray(const napi_env& env,
2228     const char* fieldStr, const std::list<Uri> listValue, napi_value& result)
2229 {
2230     napi_value value = nullptr;
2231     napi_status status = napi_create_array_with_length(env, listValue.size(), &value);
2232     if (status != napi_ok) {
2233         NAPI_ERR_LOG("Create array error! field: %{public}s", fieldStr);
2234         return status;
2235     }
2236     int elementIndex = 0;
2237     for (auto uri : listValue) {
2238         napi_value uriRet = nullptr;
2239         napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &uriRet);
2240         status = napi_set_element(env, value, elementIndex++, uriRet);
2241         if (status != napi_ok) {
2242             NAPI_ERR_LOG("Set lite item failed, error: %d", status);
2243         }
2244     }
2245     status = napi_set_named_property(env, result, fieldStr, value);
2246     if (status != napi_ok) {
2247         NAPI_ERR_LOG("Set array named property error! field: %{public}s", fieldStr);
2248     }
2249 
2250     return status;
2251 }
2252 
SetSubUris(const napi_env & env,const shared_ptr<MessageParcel> parcel,napi_value & result)2253 static napi_status SetSubUris(const napi_env& env, const shared_ptr<MessageParcel> parcel, napi_value& result)
2254 {
2255     uint32_t len = 0;
2256     napi_status status = napi_invalid_arg;
2257     if (!parcel->ReadUint32(len)) {
2258         NAPI_ERR_LOG("Failed to read sub uri list length");
2259         return status;
2260     }
2261     napi_value subUriArray = nullptr;
2262     napi_create_array_with_length(env, len, &subUriArray);
2263     int subElementIndex = 0;
2264     for (uint32_t i = 0; i < len; i++) {
2265         string subUri = parcel->ReadString();
2266         if (subUri.empty()) {
2267             NAPI_ERR_LOG("Failed to read sub uri");
2268             return status;
2269         }
2270         napi_value subUriRet = nullptr;
2271         napi_create_string_utf8(env, subUri.c_str(), NAPI_AUTO_LENGTH, &subUriRet);
2272         napi_set_element(env, subUriArray, subElementIndex++, subUriRet);
2273     }
2274     status = napi_set_named_property(env, result, "extraUris", subUriArray);
2275     if (status != napi_ok) {
2276         NAPI_ERR_LOG("Set subUri named property error!");
2277     }
2278     return status;
2279 }
2280 
GetTrashAlbumUri()2281 string ChangeListenerNapi::GetTrashAlbumUri()
2282 {
2283     if (!trashAlbumUri_.empty()) {
2284         return trashAlbumUri_;
2285     }
2286     string queryUri = UFM_QUERY_PHOTO_ALBUM;
2287     Uri uri(queryUri);
2288     int errCode = 0;
2289     DataSharePredicates predicates;
2290     predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::TRASH));
2291     vector<string> columns;
2292     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
2293     unique_ptr<FetchResult<PhotoAlbum>> albumSet = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
2294     if (albumSet == nullptr) {
2295         return trashAlbumUri_;
2296     }
2297     if (albumSet->GetCount() != 1) {
2298         return trashAlbumUri_;
2299     }
2300     trashAlbumUri_ = albumSet->GetFirstObject()->GetAlbumUri();
2301     return trashAlbumUri_;
2302 }
2303 
SolveOnChange(napi_env env,UvChangeMsg * msg)2304 napi_value ChangeListenerNapi::SolveOnChange(napi_env env, UvChangeMsg *msg)
2305 {
2306     static napi_value result;
2307     if (msg->changeInfo_.uris_.empty()) {
2308         napi_get_undefined(env, &result);
2309         return result;
2310     }
2311     napi_create_object(env, &result);
2312     SetValueArray(env, "uris", msg->changeInfo_.uris_, result);
2313     if (msg->changeInfo_.uris_.size() == DEFAULT_ALBUM_COUNT) {
2314         if (msg->changeInfo_.uris_.front().ToString().compare(GetTrashAlbumUri()) == 0) {
2315             if (!MediaLibraryNapiUtils::IsSystemApp()) {
2316                 napi_get_undefined(env, &result);
2317                 return nullptr;
2318             }
2319         }
2320     }
2321     if (msg->data_ != nullptr && msg->changeInfo_.size_ > 0) {
2322         if ((int)msg->changeInfo_.changeType_ == ChangeType::INSERT) {
2323             SetValueInt32(env, "type", (int)NotifyType::NOTIFY_ALBUM_ADD_ASSERT, result);
2324         } else {
2325             SetValueInt32(env, "type", (int)NotifyType::NOTIFY_ALBUM_REMOVE_ASSET, result);
2326         }
2327         shared_ptr<MessageParcel> parcel = make_shared<MessageParcel>();
2328         if (parcel->ParseFrom(reinterpret_cast<uintptr_t>(msg->data_), msg->changeInfo_.size_)) {
2329             napi_status status = SetSubUris(env, parcel, result);
2330             if (status != napi_ok) {
2331                 NAPI_ERR_LOG("Set subArray named property error! field: subUris");
2332                 return nullptr;
2333             }
2334         }
2335     } else {
2336         SetValueInt32(env, "type", (int)msg->changeInfo_.changeType_, result);
2337     }
2338     return result;
2339 }
2340 
OnChange(MediaChangeListener & listener,const napi_ref cbRef)2341 void ChangeListenerNapi::OnChange(MediaChangeListener &listener, const napi_ref cbRef)
2342 {
2343     uv_loop_s *loop = nullptr;
2344     napi_get_uv_event_loop(env_, &loop);
2345     if (loop == nullptr) {
2346         return;
2347     }
2348 
2349     uv_work_t *work = new (nothrow) uv_work_t;
2350     if (work == nullptr) {
2351         return;
2352     }
2353 
2354     UvChangeMsg *msg = new (std::nothrow) UvChangeMsg(env_, cbRef, listener.changeInfo, listener.strUri);
2355     if (msg == nullptr) {
2356         delete work;
2357         return;
2358     }
2359     if (!listener.changeInfo.uris_.empty()) {
2360         if (listener.changeInfo.changeType_ == DataShare::DataShareObserver::ChangeType::OTHER) {
2361             NAPI_ERR_LOG("changeInfo.changeType_ is other");
2362             return;
2363         }
2364         if (msg->changeInfo_.size_ > 0) {
2365             msg->data_ = (uint8_t *)malloc(msg->changeInfo_.size_);
2366             if (msg->data_ == nullptr) {
2367                 NAPI_ERR_LOG("new msg->data failed");
2368                 return;
2369             }
2370             int copyRet = memcpy_s(msg->data_, msg->changeInfo_.size_, msg->changeInfo_.data_, msg->changeInfo_.size_);
2371             if (copyRet != 0) {
2372                 NAPI_ERR_LOG("Parcel data copy failed, err = %{public}d", copyRet);
2373             }
2374         }
2375     }
2376     work->data = reinterpret_cast<void *>(msg);
2377 
2378     int ret = uv_queue_work(loop, work, [](uv_work_t *w) {}, [](uv_work_t *w, int s) {
2379             // js thread
2380             if (w == nullptr) {
2381                 return;
2382             }
2383 
2384             UvChangeMsg *msg = reinterpret_cast<UvChangeMsg *>(w->data);
2385             do {
2386                 if (msg == nullptr) {
2387                     NAPI_ERR_LOG("UvChangeMsg is null");
2388                     break;
2389                 }
2390                 napi_env env = msg->env_;
2391 
2392                 napi_value jsCallback = nullptr;
2393                 napi_status status = napi_get_reference_value(env, msg->ref_, &jsCallback);
2394                 if (status != napi_ok) {
2395                     NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
2396                     break;
2397                 }
2398                 napi_value retVal = nullptr;
2399                 napi_value result[ARGS_ONE];
2400                 result[PARAM0] = ChangeListenerNapi::SolveOnChange(env, msg);
2401                 if (result[PARAM0] == nullptr) {
2402                     break;
2403                 }
2404                 napi_call_function(env, nullptr, jsCallback, ARGS_ONE, result, &retVal);
2405                 if (status != napi_ok) {
2406                     NAPI_ERR_LOG("CallJs napi_call_function fail, status: %{public}d", status);
2407                     break;
2408                 }
2409             } while (0);
2410             delete msg;
2411             delete w;
2412     });
2413     if (ret != 0) {
2414         NAPI_ERR_LOG("Failed to execute libuv work queue, ret: %{public}d", ret);
2415         delete msg;
2416         delete work;
2417     }
2418 }
2419 
GetListenerType(const string & str) const2420 int32_t MediaLibraryNapi::GetListenerType(const string &str) const
2421 {
2422     auto iter = ListenerTypeMaps.find(str);
2423     if (iter == ListenerTypeMaps.end()) {
2424         NAPI_ERR_LOG("Invalid Listener Type %{public}s", str.c_str());
2425         return INVALID_LISTENER;
2426     }
2427 
2428     return iter->second;
2429 }
2430 
RegisterChange(napi_env env,const string & type,ChangeListenerNapi & listObj)2431 void MediaLibraryNapi::RegisterChange(napi_env env, const string &type, ChangeListenerNapi &listObj)
2432 {
2433     NAPI_DEBUG_LOG("Register change type = %{public}s", type.c_str());
2434 
2435     int32_t typeEnum = GetListenerType(type);
2436     switch (typeEnum) {
2437         case AUDIO_LISTENER:
2438             listObj.audioDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_AUDIO);
2439             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
2440             break;
2441         case VIDEO_LISTENER:
2442             listObj.videoDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_VIDEO);
2443             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
2444             break;
2445         case IMAGE_LISTENER:
2446             listObj.imageDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_IMAGE);
2447             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
2448             break;
2449         case FILE_LISTENER:
2450             listObj.fileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_FILE);
2451             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
2452             break;
2453         case SMARTALBUM_LISTENER:
2454             listObj.smartAlbumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_SMARTALBUM);
2455             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
2456                 listObj.smartAlbumDataObserver_);
2457             break;
2458         case DEVICE_LISTENER:
2459             listObj.deviceDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_DEVICE);
2460             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
2461             break;
2462         case REMOTEFILE_LISTENER:
2463             listObj.remoteFileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_REMOTEFILE);
2464             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
2465             break;
2466         case ALBUM_LISTENER:
2467             listObj.albumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_ALBUM);
2468             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
2469             break;
2470         default:
2471             NAPI_ERR_LOG("Invalid Media Type!");
2472     }
2473 }
2474 
RegisterNotifyChange(napi_env env,const std::string & uri,bool isDerived,napi_ref ref,ChangeListenerNapi & listObj)2475 void MediaLibraryNapi::RegisterNotifyChange(napi_env env,
2476     const std::string &uri, bool isDerived, napi_ref ref, ChangeListenerNapi &listObj)
2477 {
2478     Uri notifyUri(uri);
2479     shared_ptr<MediaOnNotifyObserver> observer= make_shared<MediaOnNotifyObserver>(listObj, uri, ref);
2480     UserFileClient::RegisterObserverExt(notifyUri,
2481         static_cast<shared_ptr<DataShare::DataShareObserver>>(observer), isDerived);
2482     lock_guard<mutex> lock(sOnOffMutex_);
2483     listObj.observers_.push_back(observer);
2484 }
2485 
JSOnCallback(napi_env env,napi_callback_info info)2486 napi_value MediaLibraryNapi::JSOnCallback(napi_env env, napi_callback_info info)
2487 {
2488     MediaLibraryTracer tracer;
2489     tracer.Start("JSOnCallback");
2490     napi_value undefinedResult = nullptr;
2491     napi_get_undefined(env, &undefinedResult);
2492     size_t argc = ARGS_TWO;
2493     napi_value argv[ARGS_TWO] = {nullptr};
2494     napi_value thisVar = nullptr;
2495     GET_JS_ARGS(env, info, argc, argv, thisVar);
2496     NAPI_ASSERT(env, argc == ARGS_TWO, "requires 2 parameters");
2497     MediaLibraryNapi *obj = nullptr;
2498     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
2499     if (status == napi_ok && obj != nullptr) {
2500         napi_valuetype valueType = napi_undefined;
2501         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
2502             napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
2503             return undefinedResult;
2504         }
2505         char buffer[ARG_BUF_SIZE];
2506         size_t res = 0;
2507         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
2508             NAPI_ERR_LOG("Failed to get value string utf8 for type");
2509             return undefinedResult;
2510         }
2511         string type = string(buffer);
2512         const int32_t refCount = 1;
2513         napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOnRef_);
2514         tracer.Start("RegisterChange");
2515         obj->RegisterChange(env, type, *g_listObj);
2516         tracer.Finish();
2517     }
2518     return undefinedResult;
2519 }
2520 
CheckRef(napi_env env,napi_ref ref,ChangeListenerNapi & listObj,bool isOff,const string & uri)2521 bool MediaLibraryNapi::CheckRef(napi_env env,
2522     napi_ref ref, ChangeListenerNapi &listObj, bool isOff, const string &uri)
2523 {
2524     napi_value offCallback = nullptr;
2525     napi_status status = napi_get_reference_value(env, ref, &offCallback);
2526     if (status != napi_ok) {
2527         NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
2528         return false;
2529     }
2530     bool isSame = false;
2531     shared_ptr<DataShare::DataShareObserver> obs;
2532     string obsUri;
2533     {
2534         lock_guard<mutex> lock(sOnOffMutex_);
2535         for (auto it = listObj.observers_.begin(); it < listObj.observers_.end(); it++) {
2536             napi_value onCallback = nullptr;
2537             status = napi_get_reference_value(env, (*it)->ref_, &onCallback);
2538             if (status != napi_ok) {
2539                 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
2540                 return false;
2541             }
2542             napi_strict_equals(env, offCallback, onCallback, &isSame);
2543             if (isSame) {
2544                 obsUri = (*it)->uri_;
2545                 if ((isOff) && (uri.compare(obsUri) == 0)) {
2546                     obs = static_cast<shared_ptr<DataShare::DataShareObserver>>(*it);
2547                     listObj.observers_.erase(it);
2548                     break;
2549                 }
2550                 if (uri.compare(obsUri) != 0) {
2551                     return true;
2552                 }
2553                 return false;
2554             }
2555         }
2556     }
2557     if (isSame && isOff) {
2558         if (obs != nullptr) {
2559             UserFileClient::UnregisterObserverExt(Uri(obsUri), obs);
2560         }
2561     }
2562     return true;
2563 }
2564 
UserFileMgrOnCallback(napi_env env,napi_callback_info info)2565 napi_value MediaLibraryNapi::UserFileMgrOnCallback(napi_env env, napi_callback_info info)
2566 {
2567     MediaLibraryTracer tracer;
2568     tracer.Start("UserFileMgrOnCallback");
2569     napi_value undefinedResult = nullptr;
2570     napi_get_undefined(env, &undefinedResult);
2571     size_t argc = ARGS_THREE;
2572     napi_value argv[ARGS_THREE] = {nullptr};
2573     napi_value thisVar = nullptr;
2574     GET_JS_ARGS(env, info, argc, argv, thisVar);
2575     if (argc == ARGS_TWO) {
2576         return JSOnCallback(env, info);
2577     }
2578     NAPI_ASSERT(env, argc == ARGS_THREE, "requires 3 parameters");
2579     MediaLibraryNapi *obj = nullptr;
2580     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
2581     if (status == napi_ok && obj != nullptr) {
2582         napi_valuetype valueType = napi_undefined;
2583         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
2584             napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_boolean ||
2585             napi_typeof(env, argv[PARAM2], &valueType) != napi_ok || valueType != napi_function) {
2586             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2587             return undefinedResult;
2588         }
2589         char buffer[ARG_BUF_SIZE];
2590         size_t res = 0;
2591         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
2592             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2593             return undefinedResult;
2594         }
2595         string uri = string(buffer);
2596         bool isDerived = false;
2597         if (napi_get_value_bool(env, argv[PARAM1], &isDerived) != napi_ok) {
2598             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2599             return undefinedResult;
2600         }
2601         const int32_t refCount = 1;
2602         napi_ref cbOnRef;
2603         napi_create_reference(env, argv[PARAM2], refCount, &cbOnRef);
2604         tracer.Start("RegisterNotifyChange");
2605         if (CheckRef(env, cbOnRef, *g_listObj, false, uri)) {
2606             obj->RegisterNotifyChange(env, uri, isDerived, cbOnRef, *g_listObj);
2607         } else {
2608             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2609             return undefinedResult;
2610         }
2611         tracer.Finish();
2612     }
2613     return undefinedResult;
2614 }
2615 
UnregisterChange(napi_env env,const string & type,ChangeListenerNapi & listObj)2616 void MediaLibraryNapi::UnregisterChange(napi_env env, const string &type, ChangeListenerNapi &listObj)
2617 {
2618     NAPI_DEBUG_LOG("Unregister change type = %{public}s", type.c_str());
2619 
2620     MediaType mediaType;
2621     int32_t typeEnum = GetListenerType(type);
2622 
2623     switch (typeEnum) {
2624         case AUDIO_LISTENER:
2625             CHECK_NULL_PTR_RETURN_VOID(listObj.audioDataObserver_, "Failed to obtain audio data observer");
2626             mediaType = MEDIA_TYPE_AUDIO;
2627             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
2628             listObj.audioDataObserver_ = nullptr;
2629             break;
2630         case VIDEO_LISTENER:
2631             CHECK_NULL_PTR_RETURN_VOID(listObj.videoDataObserver_, "Failed to obtain video data observer");
2632             mediaType = MEDIA_TYPE_VIDEO;
2633             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
2634             listObj.videoDataObserver_ = nullptr;
2635             break;
2636         case IMAGE_LISTENER:
2637             CHECK_NULL_PTR_RETURN_VOID(listObj.imageDataObserver_, "Failed to obtain image data observer");
2638             mediaType = MEDIA_TYPE_IMAGE;
2639             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
2640             listObj.imageDataObserver_ = nullptr;
2641             break;
2642         case FILE_LISTENER:
2643             CHECK_NULL_PTR_RETURN_VOID(listObj.fileDataObserver_, "Failed to obtain file data observer");
2644             mediaType = MEDIA_TYPE_FILE;
2645             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
2646             listObj.fileDataObserver_ = nullptr;
2647             break;
2648         case SMARTALBUM_LISTENER:
2649             CHECK_NULL_PTR_RETURN_VOID(listObj.smartAlbumDataObserver_, "Failed to obtain smart album data observer");
2650             mediaType = MEDIA_TYPE_SMARTALBUM;
2651             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
2652                 listObj.smartAlbumDataObserver_);
2653             listObj.smartAlbumDataObserver_ = nullptr;
2654             break;
2655         case DEVICE_LISTENER:
2656             CHECK_NULL_PTR_RETURN_VOID(listObj.deviceDataObserver_, "Failed to obtain device data observer");
2657             mediaType = MEDIA_TYPE_DEVICE;
2658             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
2659             listObj.deviceDataObserver_ = nullptr;
2660             break;
2661         case REMOTEFILE_LISTENER:
2662             CHECK_NULL_PTR_RETURN_VOID(listObj.remoteFileDataObserver_, "Failed to obtain remote file data observer");
2663             mediaType = MEDIA_TYPE_REMOTEFILE;
2664             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
2665             listObj.remoteFileDataObserver_ = nullptr;
2666             break;
2667         case ALBUM_LISTENER:
2668             CHECK_NULL_PTR_RETURN_VOID(listObj.albumDataObserver_, "Failed to obtain album data observer");
2669             mediaType = MEDIA_TYPE_ALBUM;
2670             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
2671             listObj.albumDataObserver_ = nullptr;
2672             break;
2673         default:
2674             NAPI_ERR_LOG("Invalid Media Type");
2675             return;
2676     }
2677 
2678     if (listObj.cbOffRef_ != nullptr) {
2679         MediaChangeListener listener;
2680         listener.mediaType = mediaType;
2681         listObj.OnChange(listener, listObj.cbOffRef_);
2682     }
2683 }
2684 
UnRegisterNotifyChange(napi_env env,const std::string & uri,napi_ref ref,ChangeListenerNapi & listObj)2685 void MediaLibraryNapi::UnRegisterNotifyChange(napi_env env,
2686     const std::string &uri, napi_ref ref, ChangeListenerNapi &listObj)
2687 {
2688     if (ref != nullptr) {
2689         CheckRef(env, ref, listObj, true, uri);
2690         return;
2691     }
2692     if (listObj.observers_.size() == 0) {
2693         return;
2694     }
2695     std::vector<std::shared_ptr<MediaOnNotifyObserver>> offObservers;
2696     {
2697         lock_guard<mutex> lock(sOnOffMutex_);
2698         for (auto iter = listObj.observers_.begin(); iter != listObj.observers_.end();) {
2699             if (uri.compare((*iter)->uri_) == 0) {
2700                 offObservers.push_back(*iter);
2701                 vector<shared_ptr<MediaOnNotifyObserver>>::iterator tmp = iter;
2702                 iter = listObj.observers_.erase(tmp);
2703             } else {
2704                 iter++;
2705             }
2706         }
2707     }
2708     for (auto obs : offObservers) {
2709         UserFileClient::UnregisterObserverExt(Uri(uri),
2710             static_cast<shared_ptr<DataShare::DataShareObserver>>(obs));
2711     }
2712 }
2713 
JSOffCallback(napi_env env,napi_callback_info info)2714 napi_value MediaLibraryNapi::JSOffCallback(napi_env env, napi_callback_info info)
2715 {
2716     MediaLibraryTracer tracer;
2717     tracer.Start("JSOffCallback");
2718     napi_value undefinedResult = nullptr;
2719     napi_get_undefined(env, &undefinedResult);
2720     size_t argc = ARGS_TWO;
2721     napi_value argv[ARGS_TWO] = {nullptr};
2722     napi_value thisVar = nullptr;
2723     GET_JS_ARGS(env, info, argc, argv, thisVar);
2724     NAPI_ASSERT(env, ARGS_ONE <= argc && argc <= ARGS_TWO, "requires one or two parameters");
2725     if (thisVar == nullptr || argv[PARAM0] == nullptr) {
2726         NAPI_ERR_LOG("Failed to retrieve details about the callback");
2727         return undefinedResult;
2728     }
2729     MediaLibraryNapi *obj = nullptr;
2730     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
2731     if (status == napi_ok && obj != nullptr) {
2732         napi_valuetype valueType = napi_undefined;
2733         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
2734             return undefinedResult;
2735         }
2736         if (argc == ARGS_TWO) {
2737             auto status = napi_typeof(env, argv[PARAM1], &valueType);
2738             if (status == napi_ok && (valueType == napi_undefined || valueType == napi_null)) {
2739                 argc -= 1;
2740             }
2741         }
2742         size_t res = 0;
2743         char buffer[ARG_BUF_SIZE];
2744         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
2745             NAPI_ERR_LOG("Failed to get value string utf8 for type");
2746             return undefinedResult;
2747         }
2748         string type = string(buffer);
2749         if (argc == ARGS_TWO) {
2750             if (napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function ||
2751                 g_listObj == nullptr) {
2752                 return undefinedResult;
2753             }
2754             const int32_t refCount = 1;
2755             napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOffRef_);
2756         }
2757 
2758         tracer.Start("UnregisterChange");
2759         obj->UnregisterChange(env, type, *g_listObj);
2760         tracer.Finish();
2761     }
2762 
2763     return undefinedResult;
2764 }
2765 
UserFileMgrOffCheckArgs(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)2766 static napi_value UserFileMgrOffCheckArgs(napi_env env, napi_callback_info info,
2767     unique_ptr<MediaLibraryAsyncContext> &context)
2768 {
2769     napi_value thisVar = nullptr;
2770     context->argc = ARGS_TWO;
2771     GET_JS_ARGS(env, info, context->argc, context->argv, thisVar);
2772     NAPI_ASSERT(env, ARGS_ONE <= context->argc && context->argc<= ARGS_TWO, "requires one or two parameters");
2773     if (thisVar == nullptr || context->argv[PARAM0] == nullptr) {
2774         return nullptr;
2775     }
2776 
2777     napi_valuetype valueType = napi_undefined;
2778     if (napi_typeof(env, context->argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
2779         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2780         return nullptr;
2781     }
2782 
2783     if (context->argc == ARGS_TWO) {
2784         auto status = napi_typeof(env, context->argv[PARAM1], &valueType);
2785         if (status == napi_ok && (valueType == napi_undefined || valueType == napi_null)) {
2786             context->argc -= 1;
2787         }
2788     }
2789 
2790     return thisVar;
2791 }
2792 
UserFileMgrOffCallback(napi_env env,napi_callback_info info)2793 napi_value MediaLibraryNapi::UserFileMgrOffCallback(napi_env env, napi_callback_info info)
2794 {
2795     MediaLibraryTracer tracer;
2796     tracer.Start("UserFileMgrOffCallback");
2797     napi_value undefinedResult = nullptr;
2798     napi_get_undefined(env, &undefinedResult);
2799 
2800     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2801     napi_value thisVar = UserFileMgrOffCheckArgs(env, info, asyncContext);
2802     MediaLibraryNapi *obj = nullptr;
2803     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
2804     if (status != napi_ok || obj == nullptr || g_listObj == nullptr) {
2805         return undefinedResult;
2806     }
2807     size_t res = 0;
2808     char buffer[ARG_BUF_SIZE];
2809     if (napi_get_value_string_utf8(env, asyncContext->argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
2810         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2811         return undefinedResult;
2812     }
2813 
2814     string uri = string(buffer);
2815     napi_valuetype valueType = napi_undefined;
2816     if (ListenerTypeMaps.find(uri) != ListenerTypeMaps.end()) {
2817         if (asyncContext->argc == ARGS_TWO) {
2818             if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
2819                 return undefinedResult;
2820             }
2821             const int32_t refCount = 1;
2822             napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &g_listObj->cbOffRef_);
2823         }
2824         obj->UnregisterChange(env, uri, *g_listObj);
2825         return undefinedResult;
2826     }
2827     napi_ref cbOffRef = nullptr;
2828     if (asyncContext->argc == ARGS_TWO) {
2829         if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
2830             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2831             return undefinedResult;
2832         }
2833         const int32_t refCount = 1;
2834         napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &cbOffRef);
2835     }
2836     tracer.Start("UnRegisterNotifyChange");
2837     obj->UnRegisterNotifyChange(env, uri, cbOffRef, *g_listObj);
2838     return undefinedResult;
2839 }
2840 
JSReleaseCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2841 static void JSReleaseCompleteCallback(napi_env env, napi_status status,
2842                                       MediaLibraryAsyncContext *context)
2843 {
2844     MediaLibraryTracer tracer;
2845     tracer.Start("JSReleaseCompleteCallback");
2846 
2847     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2848 
2849     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2850     jsContext->status = false;
2851     if (context->objectInfo != nullptr) {
2852         context->objectInfo->~MediaLibraryNapi();
2853         napi_create_int32(env, SUCCESS, &jsContext->data);
2854         jsContext->status = true;
2855         napi_get_undefined(env, &jsContext->error);
2856     } else {
2857         NAPI_ERR_LOG("JSReleaseCompleteCallback context->objectInfo == nullptr");
2858         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2859             "UserFileClient is invalid");
2860         napi_get_undefined(env, &jsContext->data);
2861     }
2862 
2863     tracer.Finish();
2864     if (context->work != nullptr) {
2865         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2866                                                    context->work, *jsContext);
2867     }
2868 
2869     delete context;
2870 }
2871 
JSRelease(napi_env env,napi_callback_info info)2872 napi_value MediaLibraryNapi::JSRelease(napi_env env, napi_callback_info info)
2873 {
2874     napi_status status;
2875     napi_value result = nullptr;
2876     size_t argc = ARGS_ONE;
2877     napi_value argv[ARGS_ONE] = {0};
2878     napi_value thisVar = nullptr;
2879     napi_value resource = nullptr;
2880     int32_t refCount = 1;
2881 
2882     MediaLibraryTracer tracer;
2883     tracer.Start("JSRelease");
2884 
2885     GET_JS_ARGS(env, info, argc, argv, thisVar);
2886     NAPI_ERR_LOG("NAPI_ASSERT begin %{public}zu", argc);
2887     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_ZERO), "requires 1 parameters maximum");
2888     NAPI_ERR_LOG("NAPI_ASSERT end");
2889     napi_get_undefined(env, &result);
2890 
2891     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2892     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2893     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2894         if (argc == PARAM1) {
2895             napi_valuetype valueType = napi_undefined;
2896             napi_typeof(env, argv[PARAM0], &valueType);
2897             if (valueType == napi_function) {
2898                 napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
2899             }
2900         }
2901         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
2902 
2903         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2904         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSRelease", asyncContext);
2905 
2906         status = napi_create_async_work(
2907             env, nullptr, resource, [](napi_env env, void *data) {},
2908             reinterpret_cast<CompleteCallback>(JSReleaseCompleteCallback),
2909             static_cast<void *>(asyncContext.get()), &asyncContext->work);
2910         if (status != napi_ok) {
2911             napi_get_undefined(env, &result);
2912         } else {
2913             napi_queue_async_work(env, asyncContext->work);
2914             asyncContext.release();
2915         }
2916     }
2917 
2918     return result;
2919 }
2920 
SetSmartAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<SmartAlbumAsset> & smartAlbum)2921 static void SetSmartAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<SmartAlbumAsset> &smartAlbum)
2922 {
2923     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2924     if (smartAlbum == nullptr) {
2925         NAPI_ERR_LOG("SmartAlbumAsset is nullptr");
2926         return;
2927     }
2928     if (smartAlbum->GetAlbumCapacity() == 0) {
2929         return;
2930     }
2931     string trashPrefix;
2932     if (smartAlbum->GetAlbumId() == TRASH_ALBUM_ID_VALUES) {
2933         trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " <> ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
2934     } else {
2935         trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
2936     }
2937     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
2938     context->selectionArgs.emplace_back("0");
2939     context->selectionArgs.emplace_back(to_string(smartAlbum->GetAlbumId()));
2940     DataShare::DataSharePredicates predicates;
2941     predicates.SetOrder(SMARTALBUMMAP_DB_ID + " DESC LIMIT 0,1 ");
2942     predicates.SetWhereClause(context->selection);
2943     predicates.SetWhereArgs(context->selectionArgs);
2944     vector<string> columns;
2945     Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + ASSETMAP_VIEW_NAME);
2946     int errCode = 0;
2947     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
2948     if (resultSet == nullptr) {
2949         NAPI_ERR_LOG("resultSet is nullptr, errCode is %{public}d", errCode);
2950         return;
2951     }
2952     unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
2953     unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
2954     CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetSmartAlbumCoverUri fileAsset is nullptr");
2955     string coverUri = fileAsset->GetUri();
2956     smartAlbum->SetCoverUri(coverUri);
2957     NAPI_DEBUG_LOG("coverUri is = %{private}s", smartAlbum->GetCoverUri().c_str());
2958 }
2959 
SetSmartAlbumData(SmartAlbumAsset * smartAlbumData,shared_ptr<DataShare::DataShareResultSet> resultSet,MediaLibraryAsyncContext * context)2960 static void SetSmartAlbumData(SmartAlbumAsset* smartAlbumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
2961     MediaLibraryAsyncContext *context)
2962 {
2963     CHECK_NULL_PTR_RETURN_VOID(smartAlbumData, "albumData is null");
2964     smartAlbumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_ID, resultSet, TYPE_INT32)));
2965     smartAlbumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_NAME, resultSet,
2966         TYPE_STRING)));
2967     smartAlbumData->SetAlbumCapacity(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUMASSETS_ALBUMCAPACITY,
2968         resultSet, TYPE_INT32)));
2969     MediaFileUri fileUri(MEDIA_TYPE_SMARTALBUM, to_string(smartAlbumData->GetAlbumId()), context->networkId,
2970         MEDIA_API_VERSION_DEFAULT);
2971     smartAlbumData->SetAlbumUri(fileUri.ToString());
2972     smartAlbumData->SetDescription(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_DESCRIPTION, resultSet,
2973         TYPE_STRING)));
2974     smartAlbumData->SetExpiredTime(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_EXPIRED_TIME, resultSet,
2975         TYPE_INT32)));
2976     smartAlbumData->SetCoverUri(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_COVER_URI, resultSet,
2977         TYPE_STRING)));
2978     smartAlbumData->SetResultNapiType(context->resultNapiType);
2979 }
2980 
2981 #ifndef MEDIALIBRARY_COMPATIBILITY
GetAllSmartAlbumResultDataExecute(MediaLibraryAsyncContext * context)2982 static void GetAllSmartAlbumResultDataExecute(MediaLibraryAsyncContext *context)
2983 {
2984     MediaLibraryTracer tracer;
2985     tracer.Start("GetAllSmartAlbumResultDataExecute");
2986 
2987     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2988     NAPI_INFO_LOG("context->privateAlbumType = %{public}d", context->privateAlbumType);
2989 
2990     if (context->privateAlbumType == TYPE_TRASH) {
2991         context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(TRASH_ALBUM_ID_VALUES));
2992         NAPI_INFO_LOG("context->privateAlbumType == TYPE_TRASH");
2993     }
2994     if (context->privateAlbumType == TYPE_FAVORITE) {
2995         context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(FAVOURITE_ALBUM_ID_VALUES));
2996         NAPI_INFO_LOG("context->privateAlbumType == TYPE_FAVORITE");
2997     }
2998 
2999     vector<string> columns;
3000     string uriStr = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
3001     if (!context->networkId.empty()) {
3002         uriStr = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER +
3003             "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
3004     }
3005     Uri uri(uriStr);
3006     int errCode = 0;
3007     auto resultSet = UserFileClient::Query(uri, context->predicates, columns, errCode);
3008     if (resultSet == nullptr) {
3009         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
3010         context->error = E_PERMISSION_DENIED;
3011         return;
3012     }
3013 
3014     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
3015         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
3016         context->fetchSmartAlbumResult = make_unique<FetchResult<SmartAlbumAsset>>(move(resultSet));
3017         context->fetchSmartAlbumResult->SetNetworkId(context->networkId);
3018         context->fetchSmartAlbumResult->SetResultNapiType(context->resultNapiType);
3019         return;
3020     }
3021     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3022         unique_ptr<SmartAlbumAsset> albumData = make_unique<SmartAlbumAsset>();
3023         SetSmartAlbumData(albumData.get(), resultSet, context);
3024         if (albumData->GetCoverUri().empty()) {
3025             SetSmartAlbumCoverUri(context, albumData);
3026         }
3027         context->privateSmartAlbumNativeArray.push_back(move(albumData));
3028     }
3029 }
3030 
MediaLibSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3031 static void MediaLibSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3032     unique_ptr<JSAsyncContextOutput> &jsContext)
3033 {
3034     if (context->smartAlbumData != nullptr) {
3035         NAPI_ERR_LOG("context->smartAlbumData != nullptr");
3036         jsContext->status = true;
3037         napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumData);
3038         napi_get_undefined(env, &jsContext->error);
3039         jsContext->data = albumNapiObj;
3040     } else if (!context->privateSmartAlbumNativeArray.empty()) {
3041         jsContext->status = true;
3042         napi_value albumArray = nullptr;
3043         napi_create_array(env, &albumArray);
3044         for (size_t i = 0; i < context->privateSmartAlbumNativeArray.size(); i++) {
3045             napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
3046                 context->privateSmartAlbumNativeArray[i]);
3047             napi_set_element(env, albumArray, i, albumNapiObj);
3048         }
3049         napi_get_undefined(env, &jsContext->error);
3050         jsContext->data = albumArray;
3051     } else {
3052         NAPI_ERR_LOG("No fetch file result found!");
3053         napi_get_undefined(env, &jsContext->data);
3054         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3055             "Failed to obtain Fetch File Result");
3056     }
3057 }
3058 
UserFileMgrSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3059 static void UserFileMgrSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3060     unique_ptr<JSAsyncContextOutput> &jsContext)
3061 {
3062     if (context->fetchSmartAlbumResult->GetCount() < 0) {
3063         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
3064             "find no data by options");
3065     } else {
3066         napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchSmartAlbumResult));
3067         if (fileResult == nullptr) {
3068             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3069                 "Failed to create js object for Fetch SmartAlbum Result");
3070         } else {
3071             jsContext->data = fileResult;
3072             jsContext->status = true;
3073             napi_get_undefined(env, &jsContext->error);
3074         }
3075     }
3076 }
3077 
SmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3078 static void SmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3079     unique_ptr<JSAsyncContextOutput> &jsContext)
3080 {
3081     if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
3082         MediaLibSmartAlbumsAsyncResult(env, context, jsContext);
3083     } else {
3084         UserFileMgrSmartAlbumsAsyncResult(env, context, jsContext);
3085     }
3086 }
3087 
GetPrivateAlbumCallbackComplete(napi_env env,napi_status status,void * data)3088 static void GetPrivateAlbumCallbackComplete(napi_env env, napi_status status, void *data)
3089 {
3090     MediaLibraryTracer tracer;
3091     tracer.Start("GetPrivateAlbumCallbackComplete");
3092 
3093     auto context = static_cast<MediaLibraryAsyncContext *>(data);
3094     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3095     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3096     jsContext->status = false;
3097     napi_get_undefined(env, &jsContext->error);
3098     if (context->error != ERR_DEFAULT) {
3099         napi_get_undefined(env, &jsContext->data);
3100         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3101             "Query for get fileAssets failed");
3102     } else {
3103         SmartAlbumsAsyncResult(env, context, jsContext);
3104     }
3105 
3106     tracer.Finish();
3107     if (context->work != nullptr) {
3108         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3109                                                    context->work, *jsContext);
3110     }
3111     delete context;
3112 }
3113 #endif
3114 
GetSmartAlbumResultDataExecute(MediaLibraryAsyncContext * context)3115 static void GetSmartAlbumResultDataExecute(MediaLibraryAsyncContext *context)
3116 {
3117     DataShare::DataSharePredicates predicates;
3118     predicates.SetWhereClause(context->selection);
3119     predicates.SetWhereArgs(context->selectionArgs);
3120     vector<string> columns;
3121     Uri uri(MEDIALIBRARY_DATA_URI + "/" + SMARTALBUMASSETS_VIEW_NAME);
3122     int errCode = 0;
3123     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
3124     if (resultSet == nullptr) {
3125         NAPI_ERR_LOG("ResultSet is nullptr, errCode is %{public}d", errCode);
3126         context->error = ERR_INVALID_OUTPUT;
3127         return;
3128     }
3129     if (resultSet->GoToFirstRow() == NativeRdb::E_OK) {
3130         context->smartAlbumData = make_unique<SmartAlbumAsset>();
3131         SetSmartAlbumData(context->smartAlbumData.get(), resultSet, context);
3132         SetSmartAlbumCoverUri(context, context->smartAlbumData);
3133     } else {
3134         NAPI_ERR_LOG("Failed to goToFirstRow");
3135         context->error = ERR_INVALID_OUTPUT;
3136         return;
3137     }
3138 }
3139 
SmartAlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)3140 static void SmartAlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
3141 {
3142     auto context = static_cast<MediaLibraryAsyncContext *>(data);
3143     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3144     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3145     jsContext->status = false;
3146     napi_get_undefined(env, &jsContext->error);
3147     if (context->error != ERR_DEFAULT) {
3148         napi_get_undefined(env, &jsContext->data);
3149         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3150             "Query for get smartAlbums failed");
3151     } else {
3152         if (!context->smartAlbumNativeArray.empty()) {
3153             jsContext->status = true;
3154             napi_value albumArray = nullptr;
3155             napi_create_array(env, &albumArray);
3156             for (size_t i = 0; i < context->smartAlbumNativeArray.size(); i++) {
3157                 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
3158                     context->smartAlbumNativeArray[i]);
3159                 napi_set_element(env, albumArray, i, albumNapiObj);
3160             }
3161             napi_get_undefined(env, &jsContext->error);
3162             jsContext->data = albumArray;
3163         } else {
3164             NAPI_ERR_LOG("No SmartAlbums result found!");
3165             napi_get_undefined(env, &jsContext->data);
3166             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3167                 "Failed to obtain SmartAlbums Result");
3168         }
3169     }
3170     if (context->work != nullptr) {
3171         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3172                                                    context->work, *jsContext);
3173     }
3174     delete context;
3175 }
3176 
GetJSArgsForGetSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)3177 napi_value GetJSArgsForGetSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
3178                                      MediaLibraryAsyncContext &asyncContext)
3179 {
3180     napi_value result = nullptr;
3181     auto context = &asyncContext;
3182     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
3183     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
3184     for (size_t i = 0; i < argc; i++) {
3185         napi_valuetype valueType = napi_undefined;
3186         napi_typeof(env, argv[i], &valueType);
3187         if (i == 0 && valueType == napi_number) {
3188             napi_get_value_int32(env, argv[i], &context->parentSmartAlbumId);
3189         } else if ((i == PARAM1) && valueType == napi_function) {
3190             napi_create_reference(env, argv[i], DEFAULT_REFCOUNT, &context->callbackRef);
3191             break;
3192         } else {
3193             NAPI_ASSERT(env, false, "type mismatch");
3194         }
3195     }
3196     if (context->parentSmartAlbumId < 0) {
3197         NAPI_ASSERT(env, false, "type mismatch");
3198     }
3199     napi_get_boolean(env, true, &result);
3200     return result;
3201 }
3202 
GetSmartAlbumsResultDataExecute(napi_env env,void * data)3203 static void GetSmartAlbumsResultDataExecute(napi_env env, void *data)
3204 {
3205     auto context = static_cast<MediaLibraryAsyncContext *>(data);
3206     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3207     if (context->parentSmartAlbumId < 0) {
3208         context->error = ERR_INVALID_OUTPUT;
3209         NAPI_ERR_LOG("ParentSmartAlbumId is invalid");
3210         return;
3211     }
3212     DataShare::DataSharePredicates predicates;
3213     if (context->parentSmartAlbumId == 0) {
3214         predicates.SetWhereClause(SMARTABLUMASSETS_PARENTID + " ISNULL");
3215     } else {
3216         predicates.SetWhereClause(SMARTABLUMASSETS_PARENTID + " = ? ");
3217         predicates.SetWhereArgs({ to_string(context->parentSmartAlbumId)});
3218     }
3219     vector<string> columns;
3220     Uri uri(MEDIALIBRARY_DATA_URI + "/" + SMARTALBUMASSETS_VIEW_NAME);
3221     int errCode = 0;
3222     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
3223     if (resultSet == nullptr) {
3224         NAPI_ERR_LOG("ResultSet is nullptr, errCode is %{public}d", errCode);
3225         context->error = ERR_INVALID_OUTPUT;
3226         return;
3227     }
3228     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3229         unique_ptr<SmartAlbumAsset> albumData = make_unique<SmartAlbumAsset>();
3230         SetSmartAlbumData(albumData.get(), resultSet, context);
3231         if (albumData->GetCoverUri().empty()) {
3232             SetSmartAlbumCoverUri(context, albumData);
3233         }
3234         context->smartAlbumNativeArray.push_back(move(albumData));
3235     }
3236 }
3237 
JSGetSmartAlbums(napi_env env,napi_callback_info info)3238 napi_value MediaLibraryNapi::JSGetSmartAlbums(napi_env env, napi_callback_info info)
3239 {
3240     napi_status status;
3241     napi_value result = nullptr;
3242     size_t argc = ARGS_TWO;
3243     napi_value argv[ARGS_TWO] = {0};
3244     napi_value thisVar = nullptr;
3245 
3246     GET_JS_ARGS(env, info, argc, argv, thisVar);
3247     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
3248     napi_get_undefined(env, &result);
3249     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3250     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
3251     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Async context is null");
3252     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3253     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3254         result = GetJSArgsForGetSmartAlbum(env, argc, argv, *asyncContext);
3255         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
3256         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3257         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetSmartAlbums",
3258             GetSmartAlbumsResultDataExecute, SmartAlbumsAsyncCallbackComplete);
3259     }
3260 
3261     return result;
3262 }
3263 
AddDefaultPhotoAlbumColumns(napi_env env,vector<string> & fetchColumn)3264 static napi_value AddDefaultPhotoAlbumColumns(napi_env env, vector<string> &fetchColumn)
3265 {
3266     auto validFetchColumns = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
3267     for (const auto &column : fetchColumn) {
3268         if (PhotoAlbumColumns::IsPhotoAlbumColumn(column)) {
3269             validFetchColumns.insert(column);
3270         } else {
3271             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3272             return nullptr;
3273         }
3274     }
3275     fetchColumn.assign(validFetchColumns.begin(), validFetchColumns.end());
3276 
3277     napi_value result = nullptr;
3278     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3279     return result;
3280 }
3281 
3282 #ifdef MEDIALIBRARY_COMPATIBILITY
CompatGetPrivateAlbumExecute(napi_env env,void * data)3283 static void CompatGetPrivateAlbumExecute(napi_env env, void *data)
3284 {
3285     MediaLibraryTracer tracer;
3286     tracer.Start("CompatGetPrivateAlbumExecute");
3287 
3288     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
3289     string queryUri = URI_QUERY_PHOTO_ALBUM;
3290     Uri uri(queryUri);
3291     int err = 0;
3292     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, err);
3293     if (resultSet == nullptr) {
3294         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", err);
3295         context->SaveError(err);
3296         return;
3297     }
3298     err = resultSet->GoToFirstRow();
3299     if (err != NativeRdb::E_OK) {
3300         context->SaveError(E_HAS_DB_ERROR);
3301         return;
3302     }
3303 
3304     auto albumData = make_unique<AlbumAsset>();
3305     SetAlbumData(albumData.get(), resultSet, "");
3306     CompatSetAlbumCoverUri(context, albumData);
3307     context->albumNativeArray.push_back(move(albumData));
3308 }
3309 
CompatGetPhotoAlbumQueryResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3310 static void CompatGetPhotoAlbumQueryResult(napi_env env, MediaLibraryAsyncContext *context,
3311     unique_ptr<JSAsyncContextOutput> &jsContext)
3312 {
3313     jsContext->status = true;
3314     napi_value albumArray = nullptr;
3315     CHECK_ARGS_RET_VOID(env, napi_create_array(env, &albumArray), JS_INNER_FAIL);
3316     for (size_t i = 0; i < context->albumNativeArray.size(); i++) {
3317         napi_value albumNapiObj = AlbumNapi::CreateAlbumNapi(env, context->albumNativeArray[i]);
3318         CHECK_ARGS_RET_VOID(env, napi_set_element(env, albumArray, i, albumNapiObj), JS_INNER_FAIL);
3319     }
3320     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3321     jsContext->data = albumArray;
3322 }
3323 
CompatGetPrivateAlbumComplete(napi_env env,napi_status status,void * data)3324 static void CompatGetPrivateAlbumComplete(napi_env env, napi_status status, void *data)
3325 {
3326     MediaLibraryTracer tracer;
3327     tracer.Start("JSGetPhotoAlbumsCompleteCallback");
3328 
3329     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
3330     auto jsContext = make_unique<JSAsyncContextOutput>();
3331     jsContext->status = false;
3332 
3333     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3334     if (context->error != ERR_DEFAULT || context->albumNativeArray.empty()) {
3335         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3336         context->HandleError(env, jsContext->error);
3337     } else {
3338         CompatGetPhotoAlbumQueryResult(env, context, jsContext);
3339     }
3340 
3341     tracer.Finish();
3342     if (context->work != nullptr) {
3343         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3344                                                    context->work, *jsContext);
3345     }
3346     delete context;
3347 }
3348 
ParseArgsGetPrivateAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)3349 napi_value ParseArgsGetPrivateAlbum(napi_env env, napi_callback_info info,
3350     unique_ptr<MediaLibraryAsyncContext> &context)
3351 {
3352     int32_t privateAlbumType = -1;
3353     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, context, privateAlbumType),
3354         JS_ERR_PARAMETER_INVALID);
3355     if (privateAlbumType != PrivateAlbumType::TYPE_FAVORITE && privateAlbumType != PrivateAlbumType::TYPE_TRASH) {
3356         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid private album type");
3357         return nullptr;
3358     }
3359 
3360     PhotoAlbumSubType subType = ANY;
3361     switch (privateAlbumType) {
3362         case PrivateAlbumType::TYPE_FAVORITE: {
3363             subType = PhotoAlbumSubType::FAVORITE;
3364             break;
3365         }
3366         case PrivateAlbumType::TYPE_TRASH: {
3367             subType = PhotoAlbumSubType::TRASH;
3368             break;
3369         }
3370         default: {
3371             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid private album type");
3372             return nullptr;
3373         }
3374     }
3375     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::SYSTEM));
3376     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(subType));
3377     CHECK_NULLPTR_RET(AddDefaultPhotoAlbumColumns(env, context->fetchColumn));
3378 
3379     napi_value result = nullptr;
3380     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3381     return result;
3382 }
3383 
CompatGetPrivateAlbum(napi_env env,napi_callback_info info)3384 napi_value CompatGetPrivateAlbum(napi_env env, napi_callback_info info)
3385 {
3386     auto asyncContext = make_unique<MediaLibraryAsyncContext>();
3387     CHECK_NULLPTR_RET(ParseArgsGetPrivateAlbum(env, info, asyncContext));
3388 
3389     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CompatGetPrivateAlbum",
3390         CompatGetPrivateAlbumExecute, CompatGetPrivateAlbumComplete);
3391 }
3392 #endif // MEDIALIBRARY_COMPATIBILITY
3393 
JSGetPrivateAlbum(napi_env env,napi_callback_info info)3394 napi_value MediaLibraryNapi::JSGetPrivateAlbum(napi_env env, napi_callback_info info)
3395 {
3396 #ifdef MEDIALIBRARY_COMPATIBILITY
3397     return CompatGetPrivateAlbum(env, info);
3398 #else
3399     napi_status status;
3400     napi_value result = nullptr;
3401     size_t argc = ARGS_TWO;
3402     napi_value argv[ARGS_TWO] = {0};
3403     napi_value thisVar = nullptr;
3404     const int32_t refCount = 1;
3405 
3406     GET_JS_ARGS(env, info, argc, argv, thisVar);
3407     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
3408     napi_get_undefined(env, &result);
3409     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3410     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
3411     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3412     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3413         for (size_t i = PARAM0; i < argc; i++) {
3414             napi_valuetype valueType = napi_undefined;
3415             napi_typeof(env, argv[i], &valueType);
3416             if (i == PARAM0 && valueType == napi_number) {
3417                 napi_get_value_int32(env, argv[i], &asyncContext->privateAlbumType);
3418             } else if (i == PARAM1 && valueType == napi_function) {
3419                 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
3420                 break;
3421             } else {
3422                 NAPI_ASSERT(env, false, "type mismatch");
3423             }
3424         }
3425         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPrivateAlbum",
3426             [](napi_env env, void *data) {
3427                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3428                 GetAllSmartAlbumResultDataExecute(context);
3429             }, GetPrivateAlbumCallbackComplete);
3430     }
3431     return result;
3432 #endif
3433 }
3434 
GetJSArgsForCreateSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)3435 napi_value GetJSArgsForCreateSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
3436                                         MediaLibraryAsyncContext &asyncContext)
3437 {
3438     const int32_t refCount = 1;
3439     napi_value result = nullptr;
3440     auto context = &asyncContext;
3441     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
3442     size_t res = 0;
3443     char buffer[PATH_MAX];
3444     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
3445     for (size_t i = 0; i < argc; i++) {
3446         napi_valuetype valueType = napi_undefined;
3447         napi_typeof(env, argv[i], &valueType);
3448         if (i == 0 && valueType == napi_number) {
3449             napi_get_value_int32(env, argv[i], &context->parentSmartAlbumId);
3450         } else if (i == PARAM1 && valueType == napi_string) {
3451             napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
3452         } else if (i == PARAM2 && valueType == napi_function) {
3453             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
3454             break;
3455         } else {
3456             NAPI_ASSERT(env, false, "type mismatch");
3457         }
3458     }
3459     if (context->parentSmartAlbumId < 0) {
3460         NAPI_ASSERT(env, false, "type mismatch");
3461     }
3462     string smartName = string(buffer);
3463     if (smartName.empty()) {
3464         NAPI_ASSERT(env, false, "type mismatch");
3465     }
3466     context->valuesBucket.Put(SMARTALBUM_DB_NAME, smartName);
3467     napi_get_boolean(env, true, &result);
3468     return result;
3469 }
3470 
JSCreateSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)3471 static void JSCreateSmartAlbumCompleteCallback(napi_env env, napi_status status,
3472                                                MediaLibraryAsyncContext *context)
3473 {
3474     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3475     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3476     jsContext->status = false;
3477     if (context->error == ERR_DEFAULT) {
3478         if (context->smartAlbumData == nullptr) {
3479             NAPI_ERR_LOG("No albums found");
3480             napi_get_undefined(env, &jsContext->data);
3481             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3482                 "No albums found");
3483         } else {
3484             jsContext->status = true;
3485             napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumData);
3486             jsContext->data = albumNapiObj;
3487             napi_get_undefined(env, &jsContext->error);
3488         }
3489     } else {
3490         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3491             "File asset creation failed");
3492         napi_get_undefined(env, &jsContext->data);
3493     }
3494     if (context->work != nullptr) {
3495         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3496                                                    context->work, *jsContext);
3497     }
3498     delete context;
3499 }
3500 
CreateSmartAlbumExecute(MediaLibraryAsyncContext * context)3501 static void CreateSmartAlbumExecute(MediaLibraryAsyncContext *context)
3502 {
3503     context->valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, context->parentSmartAlbumId);
3504     Uri CreateSmartAlbumUri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMOPRN + "/" +
3505                             MEDIA_SMARTALBUMOPRN_CREATEALBUM);
3506     int retVal = UserFileClient::Insert(CreateSmartAlbumUri, context->valuesBucket);
3507     if (retVal < 0) {
3508         context->SaveError(retVal);
3509         NAPI_ERR_LOG("CreateSmartAlbum failed, retVal = %{private}d", retVal);
3510         return;
3511     }
3512     context->selection = SMARTALBUM_DB_ID + " = ?";
3513     context->selectionArgs = { to_string(retVal) };
3514     GetSmartAlbumResultDataExecute(context);
3515     // If parentSmartAlbumId == 0 do not need to add to smart map
3516     if (context->parentSmartAlbumId != 0) {
3517         DataShare::DataShareValuesBucket valuesBucket;
3518         valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, context->parentSmartAlbumId);
3519         valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ALBUM_ID, retVal);
3520         NAPI_DEBUG_LOG("CreateSmartAlbumExecute retVal = %{public}d, parentSmartAlbumId = %{public}d",
3521             retVal, context->parentSmartAlbumId);
3522         Uri addAsseturi(MEDIALIBRARY_DATA_URI +
3523             "/" + MEDIA_SMARTALBUMMAPOPRN + "/" + MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM);
3524         int32_t changedRows = UserFileClient::Insert(addAsseturi, valuesBucket);
3525         context->SaveError(changedRows);
3526     }
3527 }
3528 
JSCreateSmartAlbum(napi_env env,napi_callback_info info)3529 napi_value MediaLibraryNapi::JSCreateSmartAlbum(napi_env env, napi_callback_info info)
3530 {
3531     napi_status status;
3532     napi_value result = nullptr;
3533     size_t argc = ARGS_THREE;
3534     napi_value argv[ARGS_THREE] = {0};
3535     napi_value thisVar = nullptr;
3536     napi_value resource = nullptr;
3537 
3538     GET_JS_ARGS(env, info, argc, argv, thisVar);
3539     NAPI_ASSERT(env, (argc == ARGS_TWO || argc == ARGS_THREE), "requires 3 parameters maximum");
3540     napi_get_undefined(env, &result);
3541     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3542     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
3543     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3544     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3545         result = GetJSArgsForCreateSmartAlbum(env, argc, argv, *asyncContext);
3546         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
3547         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3548         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSCreateSmartAlbum", asyncContext);
3549         status = napi_create_async_work(
3550             env, nullptr, resource, [](napi_env env, void *data) {
3551                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3552                 CreateSmartAlbumExecute(context);
3553             },
3554             reinterpret_cast<CompleteCallback>(JSCreateSmartAlbumCompleteCallback),
3555             static_cast<void *>(asyncContext.get()), &asyncContext->work);
3556         if (status != napi_ok) {
3557             napi_get_undefined(env, &result);
3558         } else {
3559             napi_queue_async_work(env, asyncContext->work);
3560             asyncContext.release();
3561         }
3562     }
3563     return result;
3564 }
3565 
JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext * context)3566 static void JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext *context)
3567 {
3568     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3569     if (context->smartAlbumId == TYPE_TRASH) {
3570         NAPI_ERR_LOG("Trash smartalbum can not be deleted");
3571         context->error = E_TRASHALBUM_CAN_NOT_DELETE;
3572         return;
3573     }
3574     if (context->smartAlbumId == TYPE_FAVORITE) {
3575         NAPI_ERR_LOG("Facorite smartalbum can not be deleted");
3576         context->error = E_FAVORITEALBUM_CAN_NOT_DELETE;
3577         return;
3578     }
3579     DataShare::DataShareValuesBucket valuesBucket;
3580     valuesBucket.Put(SMARTALBUM_DB_ID, context->smartAlbumId);
3581     Uri DeleteSmartAlbumUri(MEDIALIBRARY_DATA_URI + "/" +
3582         MEDIA_SMARTALBUMOPRN + "/" + MEDIA_SMARTALBUMOPRN_DELETEALBUM);
3583     int retVal = UserFileClient::Insert(DeleteSmartAlbumUri, valuesBucket);
3584     NAPI_DEBUG_LOG("JSDeleteSmartAlbumExecute retVal = %{private}d, smartAlbumId = %{private}d",
3585         retVal, context->smartAlbumId);
3586     if (retVal < 0) {
3587         context->SaveError(retVal);
3588     } else {
3589         context->retVal = retVal;
3590     }
3591 }
3592 
GetJSArgsForDeleteSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)3593 napi_value GetJSArgsForDeleteSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
3594                                         MediaLibraryAsyncContext &asyncContext)
3595 {
3596     napi_value result = nullptr;
3597     auto context = &asyncContext;
3598     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
3599     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
3600     for (size_t i = 0; i < argc; i++) {
3601         napi_valuetype valueType = napi_undefined;
3602         napi_typeof(env, argv[i], &valueType);
3603         if (i == 0 && valueType == napi_number) {
3604             napi_get_value_int32(env, argv[i], &context->smartAlbumId);
3605         } else if (i == PARAM1 && valueType == napi_function) {
3606             napi_create_reference(env, argv[i], DEFAULT_REFCOUNT, &context->callbackRef);
3607             break;
3608         } else {
3609             NAPI_ASSERT(env, false, "type mismatch");
3610         }
3611     }
3612     if (context->smartAlbumId < 0) {
3613         NAPI_ASSERT(env, false, "type mismatch");
3614     }
3615     napi_get_boolean(env, true, &result);
3616     return result;
3617 }
3618 
JSDeleteSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)3619 static void JSDeleteSmartAlbumCompleteCallback(napi_env env, napi_status status,
3620                                                MediaLibraryAsyncContext *context)
3621 {
3622     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3623     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3624     jsContext->status = false;
3625     if (context->error == ERR_DEFAULT) {
3626         napi_create_int32(env, context->retVal, &jsContext->data);
3627         napi_get_undefined(env, &jsContext->error);
3628         jsContext->status = true;
3629     } else {
3630         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3631             "UserFileClient is invalid");
3632         napi_get_undefined(env, &jsContext->data);
3633     }
3634     if (context->work != nullptr) {
3635         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3636                                                    context->work, *jsContext);
3637     }
3638     delete context;
3639 }
3640 
JSDeleteSmartAlbum(napi_env env,napi_callback_info info)3641 napi_value MediaLibraryNapi::JSDeleteSmartAlbum(napi_env env, napi_callback_info info)
3642 {
3643     napi_status status;
3644     napi_value result = nullptr;
3645     size_t argc = ARGS_TWO;
3646     napi_value argv[ARGS_TWO] = {0};
3647     napi_value thisVar = nullptr;
3648     napi_value resource = nullptr;
3649 
3650     GET_JS_ARGS(env, info, argc, argv, thisVar);
3651     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
3652     napi_get_undefined(env, &result);
3653     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3654     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3655     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3656         result = GetJSArgsForDeleteSmartAlbum(env, argc, argv, *asyncContext);
3657         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
3658         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3659         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSDeleteSmartAlbum", asyncContext);
3660         status = napi_create_async_work(
3661             env, nullptr, resource, [](napi_env env, void *data) {
3662                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3663                 JSDeleteSmartAlbumExecute(context);
3664             },
3665             reinterpret_cast<CompleteCallback>(JSDeleteSmartAlbumCompleteCallback),
3666             static_cast<void *>(asyncContext.get()), &asyncContext->work);
3667         if (status != napi_ok) {
3668             napi_get_undefined(env, &result);
3669         } else {
3670             napi_queue_async_work(env, asyncContext->work);
3671             asyncContext.release();
3672         }
3673     }
3674     return result;
3675 }
3676 
SetValueUtf8String(const napi_env & env,const char * fieldStr,const char * str,napi_value & result)3677 static napi_status SetValueUtf8String(const napi_env& env, const char* fieldStr, const char* str, napi_value& result)
3678 {
3679     napi_value value;
3680     napi_status status = napi_create_string_utf8(env, str, NAPI_AUTO_LENGTH, &value);
3681     if (status != napi_ok) {
3682         NAPI_ERR_LOG("Set value create utf8 string error! field: %{public}s", fieldStr);
3683         return status;
3684     }
3685     status = napi_set_named_property(env, result, fieldStr, value);
3686     if (status != napi_ok) {
3687         NAPI_ERR_LOG("Set utf8 string named property error! field: %{public}s", fieldStr);
3688     }
3689     return status;
3690 }
3691 
SetValueBool(const napi_env & env,const char * fieldStr,const bool boolvalue,napi_value & result)3692 static napi_status SetValueBool(const napi_env& env, const char* fieldStr, const bool boolvalue, napi_value& result)
3693 {
3694     napi_value value = nullptr;
3695     napi_status status = napi_get_boolean(env, boolvalue, &value);
3696     if (status != napi_ok) {
3697         NAPI_ERR_LOG("Set value create boolean error! field: %{public}s", fieldStr);
3698         return status;
3699     }
3700     status = napi_set_named_property(env, result, fieldStr, value);
3701     if (status != napi_ok) {
3702         NAPI_ERR_LOG("Set boolean named property error! field: %{public}s", fieldStr);
3703     }
3704     return status;
3705 }
3706 
PeerInfoToJsArray(const napi_env & env,const vector<unique_ptr<PeerInfo>> & vecPeerInfo,const int32_t idx,napi_value & arrayResult)3707 static void PeerInfoToJsArray(const napi_env &env, const vector<unique_ptr<PeerInfo>> &vecPeerInfo,
3708     const int32_t idx, napi_value &arrayResult)
3709 {
3710     if (idx >= (int32_t) vecPeerInfo.size()) {
3711         return;
3712     }
3713     auto info = vecPeerInfo[idx].get();
3714     if (info == nullptr) {
3715         return;
3716     }
3717     napi_value result = nullptr;
3718     napi_create_object(env, &result);
3719     SetValueUtf8String(env, "deviceName", info->deviceName.c_str(), result);
3720     SetValueUtf8String(env, "networkId", info->networkId.c_str(), result);
3721     SetValueInt32(env, "deviceTypeId", (int) info->deviceTypeId, result);
3722     SetValueBool(env, "isOnline", info->isOnline, result);
3723 
3724     napi_status status = napi_set_element(env, arrayResult, idx, result);
3725     if (status != napi_ok) {
3726         NAPI_ERR_LOG("PeerInfo To JsArray set element error: %d", status);
3727     }
3728 }
3729 
JSGetActivePeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)3730 void JSGetActivePeersCompleteCallback(napi_env env, napi_status status,
3731     MediaLibraryAsyncContext *context)
3732 {
3733     napi_value jsPeerInfoArray = nullptr;
3734 
3735     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3736 
3737     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3738     jsContext->status = false;
3739     napi_get_undefined(env, &jsContext->data);
3740 
3741     vector<string> columns;
3742     DataShare::DataSharePredicates predicates;
3743     string strQueryCondition = DEVICE_DB_DATE_MODIFIED + " = 0";
3744     predicates.SetWhereClause(strQueryCondition);
3745     predicates.SetWhereArgs(context->selectionArgs);
3746 
3747     Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYACTIVEDEVICE);
3748     int errCode = 0;
3749     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
3750         uri, predicates, columns, errCode);
3751 
3752     if (resultSet == nullptr) {
3753         NAPI_ERR_LOG("JSGetActivePeers resultSet is null, errCode is %{public}d", errCode);
3754         delete context;
3755         return;
3756     }
3757 
3758     vector<unique_ptr<PeerInfo>> peerInfoArray;
3759     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3760         unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
3761         if (peerInfo != nullptr) {
3762             peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
3763                 TYPE_STRING));
3764             peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
3765                 TYPE_STRING));
3766             peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
3767                 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
3768             peerInfo->isOnline = true;
3769             peerInfoArray.push_back(move(peerInfo));
3770         }
3771     }
3772 
3773     if (!peerInfoArray.empty() && (napi_create_array(env, &jsPeerInfoArray) == napi_ok)) {
3774         for (size_t i = 0; i < peerInfoArray.size(); ++i) {
3775             PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
3776         }
3777 
3778         jsContext->data = jsPeerInfoArray;
3779         napi_get_undefined(env, &jsContext->error);
3780         jsContext->status = true;
3781     } else {
3782         NAPI_DEBUG_LOG("No peer info found!");
3783         napi_get_undefined(env, &jsContext->data);
3784         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3785             "Failed to obtain peer info array from DB");
3786     }
3787 
3788     if (context->work != nullptr) {
3789         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3790                                                    context->work, *jsContext);
3791     }
3792 
3793     delete context;
3794 }
3795 
JSGetAllPeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)3796 void JSGetAllPeersCompleteCallback(napi_env env, napi_status status,
3797     MediaLibraryAsyncContext *context)
3798 {
3799     napi_value jsPeerInfoArray = nullptr;
3800 
3801     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3802 
3803     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3804     jsContext->status = false;
3805     napi_get_undefined(env, &jsContext->data);
3806 
3807     vector<string> columns;
3808     DataShare::DataSharePredicates predicates;
3809     predicates.SetWhereClause(context->selection);
3810     predicates.SetWhereArgs(context->selectionArgs);
3811 
3812     Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYALLDEVICE);
3813     int errCode = 0;
3814     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
3815         uri, predicates, columns, errCode);
3816 
3817     if (resultSet == nullptr) {
3818         NAPI_ERR_LOG("JSGetAllPeers resultSet is null, errCode is %{public}d", errCode);
3819         delete context;
3820         return;
3821     }
3822 
3823     vector<unique_ptr<PeerInfo>> peerInfoArray;
3824     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3825         unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
3826         if (peerInfo != nullptr) {
3827             peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
3828                 TYPE_STRING));
3829             peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
3830                 TYPE_STRING));
3831             peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
3832                 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
3833             peerInfo->isOnline = (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_DATE_MODIFIED, resultSet,
3834                 TYPE_INT32)) == 0);
3835             peerInfoArray.push_back(move(peerInfo));
3836         }
3837     }
3838 
3839     if (!peerInfoArray.empty() && (napi_create_array(env, &jsPeerInfoArray) == napi_ok)) {
3840         for (size_t i = 0; i < peerInfoArray.size(); ++i) {
3841             PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
3842         }
3843 
3844         jsContext->data = jsPeerInfoArray;
3845         napi_get_undefined(env, &jsContext->error);
3846         jsContext->status = true;
3847     } else {
3848         NAPI_DEBUG_LOG("No peer info found!");
3849         napi_get_undefined(env, &jsContext->data);
3850         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3851             "Failed to obtain peer info array from DB");
3852     }
3853 
3854     if (context->work != nullptr) {
3855         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3856                                                    context->work, *jsContext);
3857     }
3858     delete context;
3859 }
3860 
JSGetActivePeers(napi_env env,napi_callback_info info)3861 napi_value MediaLibraryNapi::JSGetActivePeers(napi_env env, napi_callback_info info)
3862 {
3863     napi_status status;
3864     napi_value result = nullptr;
3865     const int32_t refCount = 1;
3866     napi_value resource = nullptr;
3867     size_t argc = ARGS_ONE;
3868     napi_value argv[ARGS_ONE] = {0};
3869     napi_value thisVar = nullptr;
3870 
3871     MediaLibraryTracer tracer;
3872     tracer.Start("JSGetActivePeers");
3873 
3874     GET_JS_ARGS(env, info, argc, argv, thisVar);
3875     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
3876     napi_get_undefined(env, &result);
3877 
3878     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3879     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3880     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3881         if (argc == ARGS_ONE) {
3882             GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
3883         }
3884 
3885         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3886         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSGetActivePeers", asyncContext);
3887         status = napi_create_async_work(
3888             env, nullptr, resource, [](napi_env env, void *data) {},
3889             reinterpret_cast<CompleteCallback>(JSGetActivePeersCompleteCallback),
3890             static_cast<void *>(asyncContext.get()), &asyncContext->work);
3891         if (status != napi_ok) {
3892             napi_get_undefined(env, &result);
3893         } else {
3894             napi_queue_async_work(env, asyncContext->work);
3895             asyncContext.release();
3896         }
3897     }
3898 
3899     return result;
3900 }
3901 
JSGetAllPeers(napi_env env,napi_callback_info info)3902 napi_value MediaLibraryNapi::JSGetAllPeers(napi_env env, napi_callback_info info)
3903 {
3904     napi_status status;
3905     napi_value result = nullptr;
3906     const int32_t refCount = 1;
3907     napi_value resource = nullptr;
3908     size_t argc = ARGS_ONE;
3909     napi_value argv[ARGS_ONE] = {0};
3910     napi_value thisVar = nullptr;
3911 
3912     MediaLibraryTracer tracer;
3913     tracer.Start("JSGetAllPeers");
3914 
3915     GET_JS_ARGS(env, info, argc, argv, thisVar);
3916     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
3917     napi_get_undefined(env, &result);
3918 
3919     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3920     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3921     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3922         if (argc == ARGS_ONE) {
3923             GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
3924         }
3925 
3926         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3927         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSGetAllPeers", asyncContext);
3928         status = napi_create_async_work(
3929             env, nullptr, resource, [](napi_env env, void *data) {},
3930             reinterpret_cast<CompleteCallback>(JSGetAllPeersCompleteCallback),
3931             static_cast<void *>(asyncContext.get()), &asyncContext->work);
3932         if (status != napi_ok) {
3933             napi_get_undefined(env, &result);
3934         } else {
3935             napi_queue_async_work(env, asyncContext->work);
3936             asyncContext.release();
3937         }
3938     }
3939 
3940     return result;
3941 }
3942 
CloseAsset(MediaLibraryAsyncContext * context,string uri)3943 static int32_t CloseAsset(MediaLibraryAsyncContext *context, string uri)
3944 {
3945     string abilityUri = MEDIALIBRARY_DATA_URI;
3946     Uri closeAssetUri(URI_CLOSE_FILE);
3947     context->valuesBucket.Clear();
3948     context->valuesBucket.Put(MEDIA_DATA_DB_URI, uri);
3949     int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
3950     NAPI_DEBUG_LOG("File close asset %{public}d", ret);
3951     if (ret != E_SUCCESS) {
3952         context->error = ret;
3953         NAPI_ERR_LOG("File close asset fail, %{public}d", ret);
3954     }
3955     return ret;
3956 }
3957 
GetStoreMediaAssetUri(MediaLibraryAsyncContext * context,string & uri)3958 static void GetStoreMediaAssetUri(MediaLibraryAsyncContext *context, string &uri)
3959 {
3960     bool isValid = false;
3961     string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
3962     if (relativePath.find(CAMERA_DIR_VALUES) == 0 ||
3963         relativePath.find(VIDEO_DIR_VALUES) == 0 ||
3964         relativePath.find(PIC_DIR_VALUES) == 0) {
3965         uri = URI_CREATE_PHOTO;
3966     } else if (relativePath.find(AUDIO_DIR_VALUES) == 0) {
3967         uri = URI_CREATE_AUDIO;
3968     } else {
3969         uri = URI_CREATE_FILE;
3970     }
3971 }
3972 
JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext * context)3973 static void JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext *context)
3974 {
3975     string realPath;
3976     if (!PathToRealPath(context->storeMediaSrc, realPath)) {
3977         NAPI_ERR_LOG("src path is not exist, %{public}d", errno);
3978         context->error = JS_ERR_NO_SUCH_FILE;
3979         return;
3980     }
3981     context->error = JS_E_RELATIVEPATH;
3982     int32_t srcFd = open(realPath.c_str(), O_RDWR);
3983     if (srcFd == -1) {
3984         NAPI_ERR_LOG("src path open fail, %{public}d", errno);
3985         return;
3986     }
3987     struct stat statSrc;
3988     if (fstat(srcFd, &statSrc) == -1) {
3989         close(srcFd);
3990         NAPI_DEBUG_LOG("File get stat failed, %{public}d", errno);
3991         return;
3992     }
3993     string uriString;
3994     GetStoreMediaAssetUri(context, uriString);
3995     Uri createFileUri(uriString);
3996     int index = UserFileClient::Insert(createFileUri, context->valuesBucket);
3997     if (index < 0) {
3998         close(srcFd);
3999         NAPI_ERR_LOG("storeMedia fail, file already exist %{public}d", index);
4000         return;
4001     }
4002     SetFileAssetByIdV9(index, "", context);
4003     CHECK_NULL_PTR_RETURN_VOID(context->fileAsset, "JSGetStoreMediaAssetExecute: context->fileAsset is nullptr");
4004     Uri openFileUri(context->fileAsset->GetUri());
4005     int32_t destFd = UserFileClient::OpenFile(openFileUri, MEDIA_FILEMODE_READWRITE);
4006     if (destFd < 0) {
4007         context->error = destFd;
4008         NAPI_DEBUG_LOG("File open asset failed");
4009         close(srcFd);
4010         return;
4011     }
4012     if (sendfile(destFd, srcFd, nullptr, statSrc.st_size) == -1) {
4013         close(srcFd);
4014         close(destFd);
4015         CloseAsset(context, context->fileAsset->GetUri());
4016         NAPI_ERR_LOG("copy file fail %{public}d ", errno);
4017         return;
4018     }
4019     close(srcFd);
4020     close(destFd);
4021     CloseAsset(context, context->fileAsset->GetUri());
4022     context->error = ERR_DEFAULT;
4023 }
4024 
JSGetStoreMediaAssetCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4025 static void JSGetStoreMediaAssetCompleteCallback(napi_env env, napi_status status,
4026     MediaLibraryAsyncContext *context)
4027 {
4028     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4029     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4030     CHECK_NULL_PTR_RETURN_VOID(jsContext, "Async context is null");
4031     jsContext->status = false;
4032     napi_get_undefined(env, &jsContext->data);
4033     if (context->error != ERR_DEFAULT) {
4034         NAPI_ERR_LOG("JSGetStoreMediaAssetCompleteCallback failed %{public}d ", context->error);
4035         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4036             "storeMediaAsset fail");
4037     } else {
4038         napi_create_string_utf8(env, context->fileAsset->GetUri().c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
4039         jsContext->status = true;
4040         napi_get_undefined(env, &jsContext->error);
4041     }
4042 
4043     if (context->work != nullptr) {
4044         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4045                                                    context->work, *jsContext);
4046     }
4047     delete context;
4048 }
4049 
ConvertMediaType(const string & mimeType)4050 static int ConvertMediaType(const string &mimeType)
4051 {
4052     string res;
4053     // mimeType 'image/gif', 'video/mp4', 'audio/mp3', 'file/pdf'
4054     size_t slash = mimeType.find('/');
4055     if (slash != string::npos) {
4056         res = mimeType.substr(0, slash);
4057         if (res.empty()) {
4058             return MediaType::MEDIA_TYPE_FILE;
4059         }
4060     }
4061     if (res == "image") {
4062         return MediaType::MEDIA_TYPE_IMAGE;
4063     } else if (res == "video") {
4064         return MediaType::MEDIA_TYPE_VIDEO;
4065     } else if (res == "audio") {
4066         return MediaType::MEDIA_TYPE_AUDIO;
4067     }
4068     return MediaType::MEDIA_TYPE_FILE;
4069 }
4070 
GetStoreMediaAssetProper(napi_env env,napi_value param,const string & proper,string & res)4071 static bool GetStoreMediaAssetProper(napi_env env, napi_value param, const string &proper, string &res)
4072 {
4073     napi_value value = MediaLibraryNapiUtils::GetPropertyValueByName(env, param, proper.c_str());
4074     if (value == nullptr) {
4075         NAPI_ERR_LOG("GetPropertyValueByName %{public}s fail", proper.c_str());
4076         return false;
4077     }
4078     unique_ptr<char[]> tmp;
4079     bool succ;
4080     tie(succ, tmp, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, value);
4081     if (!succ) {
4082         NAPI_ERR_LOG("param %{public}s fail", proper.c_str());
4083         return false;
4084     }
4085     res = string(tmp.get());
4086     return true;
4087 }
4088 
GetDefaultDirectory(int mediaType)4089 static string GetDefaultDirectory(int mediaType)
4090 {
4091     string relativePath;
4092     if (mediaType == MediaType::MEDIA_TYPE_IMAGE) {
4093         relativePath = "Pictures/";
4094     } else if (mediaType == MediaType::MEDIA_TYPE_VIDEO) {
4095         relativePath = "Videos/";
4096     } else if (mediaType == MediaType::MEDIA_TYPE_AUDIO) {
4097         relativePath = "Audios/";
4098     } else {
4099         relativePath = "Documents/";
4100     }
4101     return relativePath;
4102 }
4103 
GetStoreMediaAssetArgs(napi_env env,napi_value param,MediaLibraryAsyncContext & asyncContext)4104 static napi_value GetStoreMediaAssetArgs(napi_env env, napi_value param,
4105     MediaLibraryAsyncContext &asyncContext)
4106 {
4107     auto context = &asyncContext;
4108     if (!GetStoreMediaAssetProper(env, param, "src", context->storeMediaSrc)) {
4109         NAPI_ERR_LOG("param get fail");
4110         return nullptr;
4111     }
4112     string fileName = MediaFileUtils::GetFileName(context->storeMediaSrc);
4113     if (fileName.empty() || (fileName.at(0) == '.')) {
4114         NAPI_ERR_LOG("src file name is not proper");
4115         context->error = JS_E_RELATIVEPATH;
4116         return nullptr;
4117     };
4118     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, fileName);
4119     string mimeType;
4120     if (!GetStoreMediaAssetProper(env, param, "mimeType", mimeType)) {
4121         NAPI_ERR_LOG("param get fail");
4122         return nullptr;
4123     }
4124     auto mediaType = ConvertMediaType(mimeType);
4125     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, mediaType);
4126     string relativePath;
4127     if (!GetStoreMediaAssetProper(env, param, "relativePath", relativePath)) {
4128         NAPI_DEBUG_LOG("optional relativePath param empty");
4129         relativePath = GetDefaultDirectory(mediaType);
4130     }
4131     context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, relativePath);
4132     NAPI_DEBUG_LOG("src:%{public}s mime:%{public}s relp:%{private}s filename:%{private}s",
4133         context->storeMediaSrc.c_str(), mimeType.c_str(), relativePath.c_str(), fileName.c_str());
4134     napi_value result = nullptr;
4135     napi_get_undefined(env, &result);
4136     return result;
4137 }
4138 
JSStoreMediaAsset(napi_env env,napi_callback_info info)4139 napi_value MediaLibraryNapi::JSStoreMediaAsset(napi_env env, napi_callback_info info)
4140 {
4141     size_t argc = ARGS_TWO;
4142     napi_value argv[ARGS_TWO] = {0};
4143     napi_value thisVar = nullptr;
4144     GET_JS_ARGS(env, info, argc, argv, thisVar);
4145     napi_value result = nullptr;
4146     napi_get_undefined(env, &result);
4147     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4148     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
4149     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4150     if ((status == napi_ok) && (asyncContext->objectInfo != nullptr)) {
4151         napi_value res = GetStoreMediaAssetArgs(env, argv[PARAM0], *asyncContext);
4152         CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, res, "Failed to obtain arguments");
4153         if (argc == ARGS_TWO) {
4154             const int32_t refCount = 1;
4155             GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
4156         }
4157         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4158         napi_value resource = nullptr;
4159         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStoreMediaAsset", asyncContext);
4160         status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
4161                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4162                 JSGetStoreMediaAssetExecute(context);
4163             },
4164             reinterpret_cast<CompleteCallback>(JSGetStoreMediaAssetCompleteCallback),
4165             static_cast<void *>(asyncContext.get()), &asyncContext->work);
4166         if (status != napi_ok) {
4167             napi_get_undefined(env, &result);
4168         } else {
4169             napi_queue_async_work(env, asyncContext->work);
4170             asyncContext.release();
4171         }
4172     }
4173     return result;
4174 }
4175 
CreateAsyncCallbackInfo(napi_env env)4176 static Ability *CreateAsyncCallbackInfo(napi_env env)
4177 {
4178     if (env == nullptr) {
4179         NAPI_ERR_LOG("env == nullptr.");
4180         return nullptr;
4181     }
4182     napi_status ret;
4183     napi_value global = 0;
4184     const napi_extended_error_info *errorInfo = nullptr;
4185     ret = napi_get_global(env, &global);
4186     if (ret != napi_ok) {
4187         napi_get_last_error_info(env, &errorInfo);
4188         NAPI_ERR_LOG("get_global=%{public}d err:%{public}s", ret, errorInfo->error_message);
4189     }
4190     napi_value abilityObj = 0;
4191     ret = napi_get_named_property(env, global, "ability", &abilityObj);
4192     if (ret != napi_ok) {
4193         napi_get_last_error_info(env, &errorInfo);
4194         NAPI_ERR_LOG("get_named_property=%{public}d e:%{public}s", ret, errorInfo->error_message);
4195     }
4196     Ability *ability = nullptr;
4197     ret = napi_get_value_external(env, abilityObj, (void **)&ability);
4198     if (ret != napi_ok) {
4199         napi_get_last_error_info(env, &errorInfo);
4200         NAPI_ERR_LOG("get_value_external=%{public}d e:%{public}s", ret, errorInfo->error_message);
4201     }
4202     return ability;
4203 }
4204 
GetImagePreviewArgsUri(napi_env env,napi_value param,MediaLibraryAsyncContext & context)4205 static napi_value GetImagePreviewArgsUri(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
4206 {
4207     uint32_t arraySize = 0;
4208     if (!MediaLibraryNapiUtils::IsArrayForNapiValue(env, param, arraySize)) {
4209         NAPI_ERR_LOG("GetImagePreviewArgs get args fail, not array");
4210         return nullptr;
4211     }
4212     string uri = "";
4213     for (uint32_t i = 0; i < arraySize; i++) {
4214         napi_value jsValue = nullptr;
4215         if ((napi_get_element(env, param, i, &jsValue)) != napi_ok) {
4216             NAPI_ERR_LOG("GetImagePreviewArgs get args fail");
4217             return nullptr;
4218         }
4219         unique_ptr<char[]> inputStr;
4220         bool succ;
4221         tie(succ, inputStr, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, jsValue);
4222         if (!succ) {
4223             NAPI_ERR_LOG("GetImagePreviewArgs get string fail");
4224             return nullptr;
4225         }
4226         uri += string(inputStr.get());
4227         uri += ",";
4228     }
4229     context.uri = uri.substr(0, uri.length() - 1);
4230     NAPI_DEBUG_LOG("GetImagePreviewArgs res %{public}s", context.uri.c_str());
4231     napi_value res;
4232     napi_get_undefined(env, &res);
4233     return res;
4234 }
4235 
GetImagePreviewArgsNum(napi_env env,napi_value param,MediaLibraryAsyncContext & context)4236 static napi_value GetImagePreviewArgsNum(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
4237 {
4238     context.imagePreviewIndex = 0;
4239     napi_valuetype valueType = napi_undefined;
4240     napi_typeof(env, param, &valueType);
4241     if (valueType != napi_number) {
4242         NAPI_ERR_LOG("not napi value");
4243         return nullptr;
4244     }
4245     if (napi_get_value_int32(env, param, &context.imagePreviewIndex) != napi_ok) {
4246         NAPI_ERR_LOG("get property value fail");
4247     }
4248     NAPI_ERR_LOG("GetImagePreviewArgs num %{public}d", context.imagePreviewIndex);
4249     napi_value res;
4250     napi_get_undefined(env, &res);
4251     return res;
4252 }
4253 
JSStartImagePreviewExecute(MediaLibraryAsyncContext * context)4254 static void JSStartImagePreviewExecute(MediaLibraryAsyncContext *context)
4255 {
4256     if (context->ability_ == nullptr) {
4257         NAPI_ERR_LOG("ability_ is not exist");
4258         context->error = ERR_INVALID_OUTPUT;
4259         return;
4260     }
4261     Want want;
4262     want.SetType("image/jpeg");
4263     want.SetAction("ohos.want.action.viewData");
4264     want.SetParam("uri", context->uri);
4265     want.SetParam("viewIndex", context->imagePreviewIndex + 1);
4266     context->error = context->ability_->StartAbility(want);
4267 }
4268 
JSGetJSStartImagePreviewCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4269 static void JSGetJSStartImagePreviewCompleteCallback(napi_env env, napi_status status,
4270     MediaLibraryAsyncContext *context)
4271 {
4272     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4273     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4274     CHECK_NULL_PTR_RETURN_VOID(jsContext, "get jsContext failed");
4275     jsContext->status = true;
4276     napi_get_undefined(env, &jsContext->data);
4277     if (context->error != 0) {
4278         jsContext->status = false;
4279         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
4280             "startImagePreview currently fail");
4281     }
4282     if (context->work != nullptr) {
4283         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4284                                                    context->work, *jsContext);
4285     }
4286     delete context;
4287 }
4288 
JSStartImagePreview(napi_env env,napi_callback_info info)4289 napi_value MediaLibraryNapi::JSStartImagePreview(napi_env env, napi_callback_info info)
4290 {
4291     size_t argc = ARGS_THREE;
4292     napi_value argv[ARGS_THREE] = {0};
4293     napi_value thisVar = nullptr;
4294     GET_JS_ARGS(env, info, argc, argv, thisVar);
4295     napi_value result = nullptr;
4296     napi_get_undefined(env, &result);
4297     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4298     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
4299     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4300     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4301         napi_value res = GetImagePreviewArgsUri(env, argv[PARAM0], *asyncContext);
4302         CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, result, "Failed to obtain arguments uri");
4303         GetImagePreviewArgsNum(env, argv[PARAM1], *asyncContext);
4304         asyncContext->ability_ = CreateAsyncCallbackInfo(env);
4305         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->ability_, result, "Failed to obtain ability");
4306         const int32_t refCount = 1;
4307         if (argc == ARGS_THREE) {
4308             GET_JS_ASYNC_CB_REF(env, argv[PARAM2], refCount, asyncContext->callbackRef);
4309         } else if (argc == ARGS_TWO && MediaLibraryNapiUtils::CheckJSArgsTypeAsFunc(env, argv[PARAM1])) {
4310             GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
4311         }
4312         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4313         napi_value resource = nullptr;
4314         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStartImagePreview", asyncContext);
4315         status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
4316                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4317                 JSStartImagePreviewExecute(context);
4318             },
4319             reinterpret_cast<CompleteCallback>(JSGetJSStartImagePreviewCompleteCallback),
4320             static_cast<void *>(asyncContext.get()), &asyncContext->work);
4321         if (status != napi_ok) {
4322             napi_get_undefined(env, &result);
4323         } else {
4324             napi_queue_async_work(env, asyncContext->work);
4325             asyncContext.release();
4326         }
4327     }
4328     return result;
4329 }
4330 
CheckCreateOption(MediaLibraryAsyncContext & context)4331 static napi_status CheckCreateOption(MediaLibraryAsyncContext &context)
4332 {
4333     bool isValid = false;
4334     int32_t subtype = context.valuesBucket.Get(PhotoColumn::PHOTO_SUBTYPE, isValid);
4335     string cameraShotKey = context.valuesBucket.Get(PhotoColumn::CAMERA_SHOT_KEY, isValid);
4336     if (isValid == true) {
4337         if (cameraShotKey.size() < CAMERA_SHOT_KEY_SIZE) {
4338             NAPI_ERR_LOG("cameraShotKey is not null with but is less than CAMERA_SHOT_KEY_SIZE");
4339             return napi_invalid_arg;
4340         }
4341         if (subtype == static_cast<int32_t>(PhotoSubType::SCREENSHOT)) {
4342             NAPI_ERR_LOG("cameraShotKey is not null with subtype is SCREENSHOT");
4343             return napi_invalid_arg;
4344         } else {
4345             context.valuesBucket.Put(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::CAMERA));
4346         }
4347     }
4348 
4349     return napi_ok;
4350 }
4351 
ParsePhotoAssetCreateOption(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)4352 static napi_status ParsePhotoAssetCreateOption(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
4353 {
4354     for (const auto &iter : PHOTO_CREATE_OPTIONS_PARAM) {
4355         string param = iter.first;
4356         bool present = false;
4357         napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
4358         CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
4359         if (!present) {
4360             continue;
4361         }
4362         napi_value value;
4363         result = napi_get_named_property(env, arg, param.c_str(), &value);
4364         CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
4365         napi_valuetype valueType = napi_undefined;
4366         result = napi_typeof(env, value, &valueType);
4367         CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
4368         if (valueType == napi_number) {
4369             int32_t number = 0;
4370             result = napi_get_value_int32(env, value, &number);
4371             CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
4372             context.valuesBucket.Put(iter.second, number);
4373         } else if (valueType == napi_boolean) {
4374             bool isTrue = false;
4375             result = napi_get_value_bool(env, value, &isTrue);
4376             CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
4377             context.valuesBucket.Put(iter.second, isTrue);
4378         } else if (valueType == napi_string) {
4379             char buffer[ARG_BUF_SIZE];
4380             size_t res = 0;
4381             result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
4382             CHECK_COND_RET(result == napi_ok, result, "failed to get string");
4383             context.valuesBucket.Put(iter.second, string(buffer));
4384         } else if (valueType == napi_undefined || valueType == napi_null) {
4385             continue;
4386         } else {
4387             NAPI_ERR_LOG("valueType %{public}d is unaccepted", static_cast<int>(valueType));
4388             return napi_invalid_arg;
4389         }
4390     }
4391 
4392     return CheckCreateOption(context);
4393 }
4394 
ParseCreateOptions(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)4395 static napi_status ParseCreateOptions(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
4396 {
4397     for (const auto &iter : CREATE_OPTIONS_PARAM) {
4398         string param = iter.first;
4399         bool present = false;
4400         napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
4401         CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
4402         if (!present) {
4403             continue;
4404         }
4405         napi_value value;
4406         result = napi_get_named_property(env, arg, param.c_str(), &value);
4407         CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
4408         napi_valuetype valueType = napi_undefined;
4409         result = napi_typeof(env, value, &valueType);
4410         CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
4411         if (valueType == napi_number) {
4412             int32_t number = 0;
4413             result = napi_get_value_int32(env, value, &number);
4414             CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
4415             context.valuesBucket.Put(iter.second, number);
4416         } else if (valueType == napi_boolean) {
4417             bool isTrue = false;
4418             result = napi_get_value_bool(env, value, &isTrue);
4419             CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
4420             context.valuesBucket.Put(iter.second, isTrue);
4421         } else if (valueType == napi_string) {
4422             char buffer[ARG_BUF_SIZE];
4423             size_t res = 0;
4424             result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
4425             CHECK_COND_RET(result == napi_ok, result, "failed to get string");
4426             context.valuesBucket.Put(iter.second, string(buffer));
4427         } else if (valueType == napi_undefined || valueType == napi_null) {
4428             continue;
4429         } else {
4430             NAPI_ERR_LOG("ParseCreateOptions failed, valueType %{public}d is unaccepted",
4431                 static_cast<int>(valueType));
4432             return napi_invalid_arg;
4433         }
4434     }
4435 
4436     return napi_ok;
4437 }
4438 
ParseArgsCreatePhotoAssetSystem(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4439 static napi_value ParseArgsCreatePhotoAssetSystem(napi_env env, napi_callback_info info,
4440     unique_ptr<MediaLibraryAsyncContext> &context)
4441 {
4442     /* Parse the first argument into displayName */
4443     napi_valuetype valueType;
4444     MediaType mediaType;
4445     string displayName;
4446     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
4447         napi_ok, "Failed to get displayName");
4448     mediaType = MediaFileUtils::GetMediaType(displayName);
4449     NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
4450     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
4451 
4452     /* Parse the second argument into albumUri if exists */
4453     string albumUri;
4454     if ((context->argc >= ARGS_TWO)) {
4455         NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ONE], &valueType) == napi_ok, "Failed to get napi type");
4456         if (valueType == napi_string) {
4457             if (MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], albumUri) == napi_ok) {
4458                 context->valuesBucket.Put(MEDIA_DATA_DB_ALARM_URI, albumUri);
4459             }
4460         } else if (valueType == napi_object) {
4461             NAPI_ASSERT(env, ParsePhotoAssetCreateOption(env, context->argv[ARGS_ONE], *context) == napi_ok,
4462                 "Parse asset create option failed");
4463         }
4464     }
4465 
4466     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
4467     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok, "Failed to get callback");
4468 
4469     napi_value result = nullptr;
4470     NAPI_CALL(env, napi_get_boolean(env, true, &result));
4471     return result;
4472 }
4473 
ParseArgsCreatePhotoAssetComponent(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4474 static napi_value ParseArgsCreatePhotoAssetComponent(napi_env env, napi_callback_info info,
4475     unique_ptr<MediaLibraryAsyncContext> &context)
4476 {
4477     /* Parse the first argument into displayName */
4478     napi_valuetype valueType;
4479     MediaType mediaType;
4480     int32_t type = 0;
4481     NAPI_ASSERT(env, napi_get_value_int32(env, context->argv[ARGS_ZERO], &type) == napi_ok,
4482         "Failed to get type value");
4483     mediaType = static_cast<MediaType>(type);
4484     NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
4485 
4486     /* Parse the second argument into albumUri if exists */
4487     string extention;
4488     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], extention) ==
4489         napi_ok, "Failed to get extention");
4490     context->valuesBucket.Put(ASSET_EXTENTION, extention);
4491 
4492     /* Parse the third argument into albumUri if exists */
4493     if (context->argc >= ARGS_THREE) {
4494         NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_TWO], &valueType) == napi_ok, "Failed to get napi type");
4495         if (valueType == napi_object) {
4496             NAPI_ASSERT(env, ParseCreateOptions(env, context->argv[ARGS_TWO], *context) == napi_ok,
4497                 "Parse asset create option failed");
4498         } else if (valueType != napi_function) {
4499             NAPI_ERR_LOG("Napi type is wrong in create options");
4500             return nullptr;
4501         }
4502     }
4503 
4504     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
4505 
4506     napi_value result = nullptr;
4507     NAPI_CALL(env, napi_get_boolean(env, true, &result));
4508     return result;
4509 }
4510 
ParseArgsCreatePhotoAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4511 static napi_value ParseArgsCreatePhotoAsset(napi_env env, napi_callback_info info,
4512     unique_ptr<MediaLibraryAsyncContext> &context)
4513 {
4514     constexpr size_t minArgs = ARGS_ONE;
4515     constexpr size_t maxArgs = ARGS_FOUR;
4516     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
4517         napi_ok, "Failed to get object info");
4518 
4519     napi_valuetype valueType;
4520     NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ZERO], &valueType) == napi_ok, "Failed to get napi type");
4521     if (valueType == napi_string) {
4522         context->isCreateByComponent = false;
4523         return ParseArgsCreatePhotoAssetSystem(env, info, context);
4524     } else if (valueType == napi_number) {
4525         context->isCreateByComponent = true;
4526         return ParseArgsCreatePhotoAssetComponent(env, info, context);
4527     } else {
4528         NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
4529         return nullptr;
4530     }
4531 }
4532 
ParseArgsCreateAudioAssetSystem(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4533 static napi_value ParseArgsCreateAudioAssetSystem(napi_env env, napi_callback_info info,
4534     unique_ptr<MediaLibraryAsyncContext> &context)
4535 {
4536     /* Parse the first argument into displayName */
4537     string displayName;
4538     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
4539         napi_ok, "Failed to get displayName");
4540 
4541     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, MEDIA_TYPE_AUDIO);
4542     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
4543 
4544     napi_value result = nullptr;
4545     NAPI_CALL(env, napi_get_boolean(env, true, &result));
4546     return result;
4547 }
4548 
ParseArgsCreateAudioAssetComponent(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4549 static napi_value ParseArgsCreateAudioAssetComponent(napi_env env, napi_callback_info info,
4550     unique_ptr<MediaLibraryAsyncContext> &context)
4551 {
4552     /* Parse the first argument into displayName */
4553     napi_valuetype valueType;
4554     MediaType mediaType;
4555     int32_t type = 0;
4556     NAPI_ASSERT(env, napi_get_value_int32(env, context->argv[ARGS_ZERO], &type) == napi_ok,
4557         "Failed to get type value");
4558     mediaType = static_cast<MediaType>(type);
4559     NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_AUDIO), "invalid file type");
4560 
4561     /* Parse the second argument into albumUri if exists */
4562     string extention;
4563     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], extention) ==
4564         napi_ok, "Failed to get extention");
4565     context->valuesBucket.Put(ASSET_EXTENTION, extention);
4566 
4567     /* Parse the third argument into albumUri if exists */
4568     if (context->argc >= ARGS_THREE) {
4569         NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_TWO], &valueType) == napi_ok, "Failed to get napi type");
4570         if (valueType == napi_object) {
4571             NAPI_ASSERT(env, ParseCreateOptions(env, context->argv[ARGS_TWO], *context) == napi_ok,
4572                 "Parse asset create option failed");
4573         } else if (valueType != napi_function) {
4574             NAPI_ERR_LOG("Napi type is wrong in create options");
4575             return nullptr;
4576         }
4577     }
4578 
4579     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
4580     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok, "Failed to get callback");
4581 
4582     napi_value result = nullptr;
4583     NAPI_CALL(env, napi_get_boolean(env, true, &result));
4584     return result;
4585 }
4586 
ParseArgsCreateAudioAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4587 static napi_value ParseArgsCreateAudioAsset(napi_env env, napi_callback_info info,
4588     unique_ptr<MediaLibraryAsyncContext> &context)
4589 {
4590     constexpr size_t minArgs = ARGS_ONE;
4591     constexpr size_t maxArgs = ARGS_FOUR;
4592     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
4593         napi_ok, "Failed to get object info");
4594 
4595     napi_valuetype valueType;
4596     NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ZERO], &valueType) == napi_ok, "Failed to get napi type");
4597     if (valueType == napi_string) {
4598         context->isCreateByComponent = false;
4599         return ParseArgsCreateAudioAssetSystem(env, info, context);
4600     } else if (valueType == napi_number) {
4601         context->isCreateByComponent = true;
4602         return ParseArgsCreateAudioAssetComponent(env, info, context);
4603     } else {
4604         NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
4605         return nullptr;
4606     }
4607 }
4608 
ParseArgsGetAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4609 static napi_value ParseArgsGetAssets(napi_env env, napi_callback_info info,
4610     unique_ptr<MediaLibraryAsyncContext> &context)
4611 {
4612     constexpr size_t minArgs = ARGS_ONE;
4613     constexpr size_t maxArgs = ARGS_TWO;
4614     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
4615         JS_ERR_PARAMETER_INVALID);
4616 
4617     /* Parse the first argument */
4618     CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM0], ASSET_FETCH_OPT, context),
4619         JS_INNER_FAIL);
4620     auto &predicates = context->predicates;
4621     switch (context->assetType) {
4622         case TYPE_AUDIO: {
4623             CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
4624                 AudioColumn::IsAudioColumn));
4625             break;
4626         }
4627         case TYPE_PHOTO: {
4628             CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
4629                 PhotoColumn::IsPhotoColumn));
4630             break;
4631         }
4632         default: {
4633             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
4634             return nullptr;
4635         }
4636     }
4637     predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
4638     predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
4639     if (context->assetType == TYPE_PHOTO) {
4640         predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
4641     }
4642 
4643     napi_value result = nullptr;
4644     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
4645     return result;
4646 }
4647 
ParseArgsIndexUri(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,string & uri,string & albumUri)4648 static napi_status ParseArgsIndexUri(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, string &uri,
4649     string &albumUri)
4650 {
4651     CHECK_STATUS_RET(MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], uri),
4652         "Failed to get first string argument");
4653     CHECK_STATUS_RET(MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], albumUri),
4654         "Failed to get second string argument");
4655     return napi_ok;
4656 }
4657 
ParseArgsIndexof(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4658 static napi_value ParseArgsIndexof(napi_env env, napi_callback_info info,
4659     unique_ptr<MediaLibraryAsyncContext> &context)
4660 {
4661     constexpr size_t minArgs = ARGS_THREE;
4662     constexpr size_t maxArgs = ARGS_FOUR;
4663     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
4664         JS_ERR_PARAMETER_INVALID);
4665 
4666     string uri;
4667     string album;
4668     CHECK_ARGS(env, ParseArgsIndexUri(env, context, uri, album), JS_INNER_FAIL);
4669     CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM2], ASSET_FETCH_OPT, context),
4670         JS_INNER_FAIL);
4671     auto &predicates = context->predicates;
4672     predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
4673     predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
4674     predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
4675 
4676     context->fetchColumn.clear();
4677     MediaFileUri photoUri(uri);
4678     CHECK_COND(env, photoUri.GetUriType() == API10_PHOTO_URI, JS_ERR_PARAMETER_INVALID);
4679     context->fetchColumn.emplace_back(photoUri.GetFileId());
4680     if (!album.empty()) {
4681         MediaFileUri albumUri(album);
4682         CHECK_COND(env, albumUri.GetUriType() == API10_PHOTOALBUM_URI, JS_ERR_PARAMETER_INVALID);
4683         context->fetchColumn.emplace_back(albumUri.GetFileId());
4684     } else {
4685         context->fetchColumn.emplace_back(album);
4686     }
4687     napi_value result = nullptr;
4688     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
4689     return result;
4690 }
4691 
JSGetAssetsExecute(napi_env env,void * data)4692 static void JSGetAssetsExecute(napi_env env, void *data)
4693 {
4694     MediaLibraryTracer tracer;
4695     tracer.Start("JSGetAssetsExecute");
4696 
4697     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
4698     string queryUri;
4699     switch (context->assetType) {
4700         case TYPE_AUDIO: {
4701             queryUri = UFM_QUERY_AUDIO;
4702             MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4703             break;
4704         }
4705         case TYPE_PHOTO: {
4706             queryUri = UFM_QUERY_PHOTO;
4707             MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4708             break;
4709         }
4710         default: {
4711             context->SaveError(-EINVAL);
4712             return;
4713         }
4714     }
4715 
4716     Uri uri(queryUri);
4717     int errCode = 0;
4718     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
4719         context->predicates, context->fetchColumn, errCode);
4720     if (resultSet == nullptr) {
4721         context->SaveError(errCode);
4722         return;
4723     }
4724     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
4725     context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
4726 }
4727 
GetPhotoIndexAsyncCallbackComplete(napi_env env,napi_status status,void * data)4728 static void GetPhotoIndexAsyncCallbackComplete(napi_env env, napi_status status, void *data)
4729 {
4730     MediaLibraryTracer tracer;
4731     tracer.Start("GetPhotoIndexAsyncCallbackComplete");
4732 
4733     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
4734     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4735 
4736     auto jsContext = make_unique<JSAsyncContextOutput>();
4737     jsContext->status = false;
4738     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_ERR_PARAMETER_INVALID);
4739     if (context->error != ERR_DEFAULT) {
4740         context->HandleError(env, jsContext->error);
4741     } else {
4742         auto fileAsset = context->fetchFileResult->GetFirstObject();
4743         int32_t count = -1;
4744         if (fileAsset != nullptr) {
4745             count = fileAsset->GetPhotoIndex();
4746         }
4747         jsContext->status = true;
4748         napi_create_int32(env, count, &jsContext->data);
4749     }
4750 
4751     tracer.Finish();
4752     if (context->work != nullptr) {
4753         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4754                                                    context->work, *jsContext);
4755     }
4756     delete context;
4757 }
4758 
GetPhotoIndexExec(napi_env env,void * data,ResultNapiType type)4759 static void GetPhotoIndexExec(napi_env env, void *data, ResultNapiType type)
4760 {
4761     MediaLibraryTracer tracer;
4762     tracer.Start("JsGetPhotoIndexExec");
4763     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
4764     string queryUri = UFM_GET_INDEX;
4765     MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4766     Uri uri(queryUri);
4767     int errCode = 0;
4768     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
4769     if (resultSet == nullptr) {
4770         context->SaveError(errCode);
4771         return;
4772     }
4773     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
4774     context->fetchFileResult->SetResultNapiType(type);
4775 }
4776 
PhotoAccessGetPhotoIndexExec(napi_env env,void * data)4777 static void PhotoAccessGetPhotoIndexExec(napi_env env, void *data)
4778 {
4779     GetPhotoIndexExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
4780 }
4781 
JsGetPhotoIndexExec(napi_env env,void * data)4782 static void JsGetPhotoIndexExec(napi_env env, void *data)
4783 {
4784     GetPhotoIndexExec(env, data, ResultNapiType::TYPE_USERFILE_MGR);
4785 }
4786 
JSGetPhotoIndex(napi_env env,napi_callback_info info)4787 napi_value MediaLibraryNapi::JSGetPhotoIndex(napi_env env, napi_callback_info info)
4788 {
4789     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4790     CHECK_NULLPTR_RET(ParseArgsIndexof(env, info, asyncContext));
4791     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoIndex",
4792         JsGetPhotoIndexExec, GetPhotoIndexAsyncCallbackComplete);
4793 }
4794 
PhotoAccessGetPhotoIndex(napi_env env,napi_callback_info info)4795 napi_value MediaLibraryNapi::PhotoAccessGetPhotoIndex(napi_env env, napi_callback_info info)
4796 {
4797     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4798     CHECK_NULLPTR_RET(ParseArgsIndexof(env, info, asyncContext));
4799     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoIndex",
4800         PhotoAccessGetPhotoIndexExec, GetPhotoIndexAsyncCallbackComplete);
4801 }
4802 
JSGetPhotoAssets(napi_env env,napi_callback_info info)4803 napi_value MediaLibraryNapi::JSGetPhotoAssets(napi_env env, napi_callback_info info)
4804 {
4805     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4806     asyncContext->assetType = TYPE_PHOTO;
4807     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
4808 
4809     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
4810         JSGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
4811 }
4812 
PhotoAccessGetAssetsExecute(napi_env env,void * data)4813 static void PhotoAccessGetAssetsExecute(napi_env env, void *data)
4814 {
4815     MediaLibraryTracer tracer;
4816     tracer.Start("JSGetAssetsExecute");
4817 
4818     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
4819     string queryUri;
4820     switch (context->assetType) {
4821         case TYPE_PHOTO: {
4822             queryUri = PAH_QUERY_PHOTO;
4823             MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4824             break;
4825         }
4826         default: {
4827             context->SaveError(-EINVAL);
4828             return;
4829         }
4830     }
4831 
4832     Uri uri(queryUri);
4833     int errCode = 0;
4834     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
4835         context->predicates, context->fetchColumn, errCode);
4836     if (resultSet == nullptr) {
4837         context->SaveError(errCode);
4838         return;
4839     }
4840     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
4841     context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
4842 }
4843 
PhotoAccessGetPhotoAssets(napi_env env,napi_callback_info info)4844 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAssets(napi_env env, napi_callback_info info)
4845 {
4846     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4847     asyncContext->assetType = TYPE_PHOTO;
4848     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
4849 
4850     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
4851         PhotoAccessGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
4852 }
4853 
JSGetAudioAssets(napi_env env,napi_callback_info info)4854 napi_value MediaLibraryNapi::JSGetAudioAssets(napi_env env, napi_callback_info info)
4855 {
4856     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4857     asyncContext->assetType = TYPE_AUDIO;
4858     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
4859 
4860     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetAudioAssets",
4861         JSGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
4862 }
4863 
GetPhotoAlbumQueryResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)4864 static void GetPhotoAlbumQueryResult(napi_env env, MediaLibraryAsyncContext *context,
4865     unique_ptr<JSAsyncContextOutput> &jsContext)
4866 {
4867     napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchPhotoAlbumResult));
4868     if (fileResult == nullptr) {
4869         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4870         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
4871             "Failed to create js object for Fetch Album Result");
4872         return;
4873     }
4874     jsContext->data = fileResult;
4875     jsContext->status = true;
4876     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4877 }
4878 
JSGetPhotoAlbumsExecute(napi_env env,void * data)4879 static void JSGetPhotoAlbumsExecute(napi_env env, void *data)
4880 {
4881     MediaLibraryTracer tracer;
4882     tracer.Start("JSGetPhotoAlbumsExecute");
4883 
4884     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
4885     string queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
4886         UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
4887     Uri uri(queryUri);
4888     int errCode = 0;
4889     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
4890     if (resultSet == nullptr) {
4891         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
4892         context->SaveError(E_HAS_DB_ERROR);
4893         return;
4894     }
4895 
4896     context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
4897     context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
4898 }
4899 
JSGetPhotoAlbumsCompleteCallback(napi_env env,napi_status status,void * data)4900 static void JSGetPhotoAlbumsCompleteCallback(napi_env env, napi_status status, void *data)
4901 {
4902     MediaLibraryTracer tracer;
4903     tracer.Start("JSGetPhotoAlbumsCompleteCallback");
4904 
4905     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
4906     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4907     jsContext->status = false;
4908     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4909     if (context->error != ERR_DEFAULT  || context->fetchPhotoAlbumResult == nullptr) {
4910         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4911         context->HandleError(env, jsContext->error);
4912     } else {
4913         GetPhotoAlbumQueryResult(env, context, jsContext);
4914     }
4915 
4916     tracer.Finish();
4917     if (context->work != nullptr) {
4918         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4919                                                    context->work, *jsContext);
4920     }
4921     delete context;
4922 }
4923 
JSGetPhotoAlbums(napi_env env,napi_callback_info info)4924 napi_value MediaLibraryNapi::JSGetPhotoAlbums(napi_env env, napi_callback_info info)
4925 {
4926     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4927     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseAlbumFetchOptCallback(env, info, asyncContext),
4928         JS_ERR_PARAMETER_INVALID);
4929     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
4930 
4931     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAlbums", JSGetPhotoAlbumsExecute,
4932         JSGetPhotoAlbumsCompleteCallback);
4933 }
4934 
UserFileMgrCreatePhotoAsset(napi_env env,napi_callback_info info)4935 napi_value MediaLibraryNapi::UserFileMgrCreatePhotoAsset(napi_env env, napi_callback_info info)
4936 {
4937     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4938     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
4939     asyncContext->assetType = TYPE_PHOTO;
4940     NAPI_ASSERT(env, ParseArgsCreatePhotoAsset(env, info, asyncContext), "Failed to parse js args");
4941 
4942     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCreatePhotoAsset",
4943         JSCreateAssetExecute, JSCreateAssetCompleteCallback);
4944 }
4945 
UserFileMgrCreateAudioAsset(napi_env env,napi_callback_info info)4946 napi_value MediaLibraryNapi::UserFileMgrCreateAudioAsset(napi_env env, napi_callback_info info)
4947 {
4948     napi_value ret = nullptr;
4949     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4950     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
4951     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
4952     asyncContext->assetType = TYPE_AUDIO;
4953     NAPI_ASSERT(env, ParseArgsCreateAudioAsset(env, info, asyncContext), "Failed to parse js args");
4954 
4955     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCreateAudioAsset",
4956         JSCreateAssetExecute, JSCreateAssetCompleteCallback);
4957 }
4958 
ParseArgsTrashAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4959 napi_value ParseArgsTrashAsset(napi_env env, napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
4960 {
4961     string uri;
4962     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, context, uri),
4963         JS_ERR_PARAMETER_INVALID);
4964     if (uri.empty()) {
4965         NapiError::ThrowError(env, JS_E_URI, "Failed to check empty uri!");
4966         return nullptr;
4967     }
4968     if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == string::npos) {
4969         NapiError::ThrowError(env, JS_E_URI, "Failed to check uri format, not a photo uri!");
4970         return nullptr;
4971     }
4972     context->uri = uri;
4973 
4974     napi_value result = nullptr;
4975     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
4976     return result;
4977 }
4978 
UserFileMgrTrashAsset(napi_env env,napi_callback_info info)4979 napi_value MediaLibraryNapi::UserFileMgrTrashAsset(napi_env env, napi_callback_info info)
4980 {
4981     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4982     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
4983     CHECK_NULLPTR_RET(ParseArgsTrashAsset(env, info, asyncContext));
4984     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrTrashAsset", JSTrashAssetExecute,
4985         JSTrashAssetCompleteCallback);
4986 }
4987 
UserFileMgrGetPrivateAlbum(napi_env env,napi_callback_info info)4988 napi_value MediaLibraryNapi::UserFileMgrGetPrivateAlbum(napi_env env, napi_callback_info info)
4989 {
4990     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4991     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
4992     CHECK_NULLPTR_RET(ParseArgsGetPrivateAlbum(env, info, asyncContext));
4993 
4994     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetPrivateAlbum",
4995         JSGetPhotoAlbumsExecute, JSGetPhotoAlbumsCompleteCallback);
4996 }
4997 
CreateMediaTypeEnum(napi_env env)4998 napi_value MediaLibraryNapi::CreateMediaTypeEnum(napi_env env)
4999 {
5000     return CreateNumberEnumProperty(env, mediaTypesEnum, sMediaTypeEnumRef_);
5001 }
5002 
CreateMediaTypeUserFileEnum(napi_env env)5003 napi_value MediaLibraryNapi::CreateMediaTypeUserFileEnum(napi_env env)
5004 {
5005     const int32_t startIdx = 1;
5006     return CreateNumberEnumProperty(env, mediaTypesUserFileEnum, sMediaTypeEnumRef_, startIdx);
5007 }
5008 
CreateDirectoryTypeEnum(napi_env env)5009 napi_value MediaLibraryNapi::CreateDirectoryTypeEnum(napi_env env)
5010 {
5011     return CreateNumberEnumProperty(env, directoryEnum, sDirectoryEnumRef_);
5012 }
5013 
CreateVirtualAlbumTypeEnum(napi_env env)5014 napi_value MediaLibraryNapi::CreateVirtualAlbumTypeEnum(napi_env env)
5015 {
5016     return CreateNumberEnumProperty(env, virtualAlbumTypeEnum, sVirtualAlbumTypeEnumRef_);
5017 }
5018 
CreatePrivateAlbumTypeEnum(napi_env env)5019 napi_value MediaLibraryNapi::CreatePrivateAlbumTypeEnum(napi_env env)
5020 {
5021     return CreateNumberEnumProperty(env, privateAlbumTypeNameEnum, sPrivateAlbumEnumRef_);
5022 }
5023 
CreateFileKeyEnum(napi_env env)5024 napi_value MediaLibraryNapi::CreateFileKeyEnum(napi_env env)
5025 {
5026     return CreateStringEnumProperty(env, FILE_KEY_ENUM_PROPERTIES, sFileKeyEnumRef_);
5027 }
5028 
UserFileMgrCreateFileKeyEnum(napi_env env)5029 napi_value MediaLibraryNapi::UserFileMgrCreateFileKeyEnum(napi_env env)
5030 {
5031     return CreateStringEnumProperty(env, USERFILEMGR_FILEKEY_ENUM_PROPERTIES, sUserFileMgrFileKeyEnumRef_);
5032 }
5033 
CreateAudioKeyEnum(napi_env env)5034 napi_value MediaLibraryNapi::CreateAudioKeyEnum(napi_env env)
5035 {
5036     return CreateStringEnumProperty(env, AUDIOKEY_ENUM_PROPERTIES, sAudioKeyEnumRef_);
5037 }
5038 
CreateImageVideoKeyEnum(napi_env env)5039 napi_value MediaLibraryNapi::CreateImageVideoKeyEnum(napi_env env)
5040 {
5041     return CreateStringEnumProperty(env, IMAGEVIDEOKEY_ENUM_PROPERTIES, sImageVideoKeyEnumRef_);
5042 }
5043 
CreatePhotoKeysEnum(napi_env env)5044 napi_value MediaLibraryNapi::CreatePhotoKeysEnum(napi_env env)
5045 {
5046     return CreateStringEnumProperty(env, IMAGEVIDEOKEY_ENUM_PROPERTIES, sPhotoKeysEnumRef_);
5047 }
5048 
CreateAlbumKeyEnum(napi_env env)5049 napi_value MediaLibraryNapi::CreateAlbumKeyEnum(napi_env env)
5050 {
5051     return CreateStringEnumProperty(env, ALBUMKEY_ENUM_PROPERTIES, sAlbumKeyEnumRef_);
5052 }
5053 
CreateAlbumTypeEnum(napi_env env)5054 napi_value MediaLibraryNapi::CreateAlbumTypeEnum(napi_env env)
5055 {
5056     napi_value result = nullptr;
5057     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
5058 
5059     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER", PhotoAlbumType::USER), JS_INNER_FAIL);
5060     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SYSTEM", PhotoAlbumType::SYSTEM), JS_INNER_FAIL);
5061 
5062     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumType_), JS_INNER_FAIL);
5063     return result;
5064 }
5065 
CreateAlbumSubTypeEnum(napi_env env)5066 napi_value MediaLibraryNapi::CreateAlbumSubTypeEnum(napi_env env)
5067 {
5068     napi_value result = nullptr;
5069     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
5070 
5071     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER_GENERIC", PhotoAlbumSubType::USER_GENERIC),
5072         JS_INNER_FAIL);
5073     for (size_t i = 0; i < systemAlbumSubType.size(); i++) {
5074         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, systemAlbumSubType[i],
5075             PhotoAlbumSubType::SYSTEM_START + i), JS_INNER_FAIL);
5076     }
5077     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "ANY", PhotoAlbumSubType::ANY), JS_INNER_FAIL);
5078 
5079     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumSubType_), JS_INNER_FAIL);
5080     return result;
5081 }
CreateDefaultChangeUriEnum(napi_env env)5082 napi_value MediaLibraryNapi::CreateDefaultChangeUriEnum(napi_env env)
5083 {
5084     return CreateStringEnumProperty(env, DEFAULT_URI_ENUM_PROPERTIES, sDefaultChangeUriRef_);
5085 }
5086 
CreateNotifyTypeEnum(napi_env env)5087 napi_value MediaLibraryNapi::CreateNotifyTypeEnum(napi_env env)
5088 {
5089     return CreateNumberEnumProperty(env, notifyTypeEnum, sNotifyType_);
5090 }
5091 
ParseArgsCreatePhotoAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5092 static napi_value ParseArgsCreatePhotoAlbum(napi_env env, napi_callback_info info,
5093     unique_ptr<MediaLibraryAsyncContext> &context)
5094 {
5095     constexpr size_t minArgs = ARGS_ONE;
5096     constexpr size_t maxArgs = ARGS_TWO;
5097     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5098         JS_ERR_PARAMETER_INVALID);
5099 
5100     /* Parse the first argument into albumName */
5101     string albumName;
5102     CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], albumName),
5103         JS_ERR_PARAMETER_INVALID);
5104 
5105     if (MediaFileUtils::CheckAlbumName(albumName) < 0) {
5106         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5107         return nullptr;
5108     }
5109     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_NAME, albumName);
5110 
5111     napi_value result = nullptr;
5112     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5113     return result;
5114 }
5115 
GetExistsPhotoAlbum(const string & albumName,MediaLibraryAsyncContext * context)5116 static void GetExistsPhotoAlbum(const string &albumName, MediaLibraryAsyncContext *context)
5117 {
5118     string queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
5119         UFM_CREATE_PHOTO_ALBUM : PAH_CREATE_PHOTO_ALBUM;
5120     Uri uri(queryUri);
5121     DataSharePredicates predicates;
5122     predicates.EqualTo(PhotoAlbumColumns::ALBUM_NAME, albumName);
5123     vector<string> columns;
5124     int errCode = 0;
5125     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
5126     auto fetchResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
5127     fetchResult->SetResultNapiType(context->resultNapiType);
5128     context->photoAlbumData = fetchResult->GetFirstObject();
5129 }
5130 
GetPhotoAlbumById(const int32_t id,const string & albumName,MediaLibraryAsyncContext * context)5131 static void GetPhotoAlbumById(const int32_t id, const string &albumName, MediaLibraryAsyncContext *context)
5132 {
5133     auto photoAlbum = make_unique<PhotoAlbum>();
5134     photoAlbum->SetAlbumId(id);
5135     photoAlbum->SetPhotoAlbumType(USER);
5136     photoAlbum->SetPhotoAlbumSubType(USER_GENERIC);
5137     photoAlbum->SetAlbumUri(PhotoAlbumColumns::ALBUM_URI_PREFIX + to_string(id));
5138     photoAlbum->SetAlbumName(albumName);
5139     photoAlbum->SetResultNapiType(context->resultNapiType);
5140     context->photoAlbumData = move(photoAlbum);
5141 }
5142 
JSCreatePhotoAlbumExecute(napi_env env,void * data)5143 static void JSCreatePhotoAlbumExecute(napi_env env, void *data)
5144 {
5145     MediaLibraryTracer tracer;
5146     tracer.Start("JSCreatePhotoAlbumExecute");
5147 
5148     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5149     string createAlbumUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
5150         UFM_CREATE_PHOTO_ALBUM : PAH_CREATE_PHOTO_ALBUM;
5151     Uri createPhotoAlbumUri(createAlbumUri);
5152     auto ret = UserFileClient::Insert(createPhotoAlbumUri, context->valuesBucket);
5153 
5154     bool isValid = false;
5155     string albumName = context->valuesBucket.Get(PhotoAlbumColumns::ALBUM_NAME, isValid);
5156     if (!isValid) {
5157         context->SaveError(-EINVAL);
5158         return;
5159     }
5160     if (ret == -1) {
5161         // The album is already existed
5162         context->SaveError(-EEXIST);
5163         GetExistsPhotoAlbum(albumName, context);
5164         return;
5165     }
5166     if (ret < 0) {
5167         context->SaveError(ret);
5168         return;
5169     }
5170     GetPhotoAlbumById(ret, albumName, context);
5171 }
5172 
GetPhotoAlbumCreateResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)5173 static void GetPhotoAlbumCreateResult(napi_env env, MediaLibraryAsyncContext *context,
5174     unique_ptr<JSAsyncContextOutput> &jsContext)
5175 {
5176     if (context->photoAlbumData == nullptr) {
5177         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5178         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
5179             "Obtain photo album asset failed");
5180         return;
5181     }
5182     napi_value jsPhotoAlbum = PhotoAlbumNapi::CreatePhotoAlbumNapi(env, context->photoAlbumData);
5183     if (jsPhotoAlbum == nullptr) {
5184         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5185         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
5186             "Failed to create js object for PhotoAlbum");
5187         return;
5188     }
5189     jsContext->data = jsPhotoAlbum;
5190     jsContext->status = true;
5191     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5192 }
5193 
HandleExistsError(napi_env env,MediaLibraryAsyncContext * context,napi_value & error)5194 static void HandleExistsError(napi_env env, MediaLibraryAsyncContext *context, napi_value &error)
5195 {
5196     if (context->photoAlbumData == nullptr) {
5197         MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, ERR_INVALID_OUTPUT,
5198             "Obtain photo album asset failed");
5199         return;
5200     }
5201     napi_value jsPhotoAlbum = PhotoAlbumNapi::CreatePhotoAlbumNapi(env, context->photoAlbumData);
5202     if (jsPhotoAlbum == nullptr) {
5203         MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, ERR_MEM_ALLOCATION,
5204             "Failed to create js object for PhotoAlbum");
5205         return;
5206     }
5207     MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, JS_ERR_FILE_EXIST, "Album has existed");
5208     napi_value propertyName;
5209     CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, "data", NAPI_AUTO_LENGTH, &propertyName), JS_INNER_FAIL);
5210     CHECK_ARGS_RET_VOID(env, napi_set_property(env, error, propertyName, jsPhotoAlbum), JS_INNER_FAIL);
5211 }
5212 
JSCreatePhotoAlbumCompleteCallback(napi_env env,napi_status status,void * data)5213 static void JSCreatePhotoAlbumCompleteCallback(napi_env env, napi_status status, void *data)
5214 {
5215     MediaLibraryTracer tracer;
5216     tracer.Start("JSCreatePhotoAlbumCompleteCallback");
5217 
5218     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5219     auto jsContext = make_unique<JSAsyncContextOutput>();
5220     jsContext->status = false;
5221     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5222     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5223     if (context->error == ERR_DEFAULT) {
5224         GetPhotoAlbumCreateResult(env, context, jsContext);
5225     } else if (context->error == JS_ERR_FILE_EXIST) {
5226         HandleExistsError(env, context, jsContext->error);
5227     } else {
5228         context->HandleError(env, jsContext->error);
5229     }
5230 
5231     tracer.Finish();
5232     if (context->work != nullptr) {
5233         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5234                                                    context->work, *jsContext);
5235     }
5236     delete context;
5237 }
5238 
CreatePhotoAlbum(napi_env env,napi_callback_info info)5239 napi_value MediaLibraryNapi::CreatePhotoAlbum(napi_env env, napi_callback_info info)
5240 {
5241     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5242     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
5243     CHECK_NULLPTR_RET(ParseArgsCreatePhotoAlbum(env, info, asyncContext));
5244 
5245     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CreatePhotoAlbum", JSCreatePhotoAlbumExecute,
5246         JSCreatePhotoAlbumCompleteCallback);
5247 }
5248 
PhotoAccessCreatePhotoAlbum(napi_env env,napi_callback_info info)5249 napi_value MediaLibraryNapi::PhotoAccessCreatePhotoAlbum(napi_env env, napi_callback_info info)
5250 {
5251     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5252     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5253     CHECK_NULLPTR_RET(ParseArgsCreatePhotoAlbum(env, info, asyncContext));
5254 
5255     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CreatePhotoAlbum", JSCreatePhotoAlbumExecute,
5256         JSCreatePhotoAlbumCompleteCallback);
5257 }
5258 
ParseArgsDeletePhotoAlbums(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5259 static napi_value ParseArgsDeletePhotoAlbums(napi_env env, napi_callback_info info,
5260     unique_ptr<MediaLibraryAsyncContext> &context)
5261 {
5262     constexpr size_t minArgs = ARGS_ONE;
5263     constexpr size_t maxArgs = ARGS_TWO;
5264     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5265         JS_ERR_PARAMETER_INVALID);
5266 
5267     /* Parse the first argument into delete album id array */
5268     vector<string> deleteIds;
5269 
5270     uint32_t len = 0;
5271     CHECK_ARGS(env, napi_get_array_length(env, context->argv[PARAM0], &len), JS_INNER_FAIL);
5272     for (uint32_t i = 0; i < len; i++) {
5273         napi_value album = nullptr;
5274         CHECK_ARGS(env, napi_get_element(env, context->argv[PARAM0], i, &album), JS_INNER_FAIL);
5275         if (album == nullptr) {
5276             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5277             return nullptr;
5278         }
5279         PhotoAlbumNapi *obj = nullptr;
5280         CHECK_ARGS(env, napi_unwrap(env, album, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
5281         if (obj == nullptr) {
5282             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5283             return nullptr;
5284         }
5285         if (!PhotoAlbum::IsUserPhotoAlbum(obj->GetPhotoAlbumType(), obj->GetPhotoAlbumSubType())) {
5286             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5287             return nullptr;
5288         }
5289         deleteIds.push_back(to_string(obj->GetAlbumId()));
5290     }
5291     if (deleteIds.empty()) {
5292         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5293         return nullptr;
5294     }
5295     context->predicates.In(PhotoAlbumColumns::ALBUM_ID, deleteIds);
5296 
5297     napi_value result = nullptr;
5298     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5299     return result;
5300 }
5301 
JSDeletePhotoAlbumsExecute(napi_env env,void * data)5302 static void JSDeletePhotoAlbumsExecute(napi_env env, void *data)
5303 {
5304     MediaLibraryTracer tracer;
5305     tracer.Start("JSDeletePhotoAlbumsExecute");
5306 
5307     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5308     string deleteAlbumUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
5309         UFM_DELETE_PHOTO_ALBUM : PAH_DELETE_PHOTO_ALBUM;
5310     Uri uri(deleteAlbumUri);
5311     int ret = UserFileClient::Delete(uri, context->predicates);
5312     if (ret < 0) {
5313         context->SaveError(ret);
5314     } else {
5315         context->retVal = ret;
5316     }
5317 }
5318 
JSDeletePhotoAlbumsCompleteCallback(napi_env env,napi_status status,void * data)5319 static void JSDeletePhotoAlbumsCompleteCallback(napi_env env, napi_status status, void *data)
5320 {
5321     MediaLibraryTracer tracer;
5322     tracer.Start("JSDeletePhotoAlbumsCompleteCallback");
5323 
5324     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
5325     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5326 
5327     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
5328     jsContext->status = false;
5329 
5330     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5331     if (context->error != ERR_DEFAULT) {
5332         context->HandleError(env, jsContext->error);
5333         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5334     } else {
5335         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->retVal, &jsContext->data), JS_INNER_FAIL);
5336         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5337         jsContext->status = true;
5338     }
5339 
5340     tracer.Finish();
5341     if (context->work != nullptr) {
5342         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5343                                                    context->work, *jsContext);
5344     }
5345     delete context;
5346 }
5347 
DeletePhotoAlbums(napi_env env,napi_callback_info info)5348 napi_value MediaLibraryNapi::DeletePhotoAlbums(napi_env env, napi_callback_info info)
5349 {
5350     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5351     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
5352     CHECK_NULLPTR_RET(ParseArgsDeletePhotoAlbums(env, info, asyncContext));
5353 
5354     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "DeletePhotoAlbums",
5355         JSDeletePhotoAlbumsExecute, JSDeletePhotoAlbumsCompleteCallback);
5356 }
5357 
PhotoAccessDeletePhotoAlbums(napi_env env,napi_callback_info info)5358 napi_value MediaLibraryNapi::PhotoAccessDeletePhotoAlbums(napi_env env, napi_callback_info info)
5359 {
5360     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5361     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5362     CHECK_NULLPTR_RET(ParseArgsDeletePhotoAlbums(env, info, asyncContext));
5363 
5364     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "DeletePhotoAlbums",
5365         JSDeletePhotoAlbumsExecute, JSDeletePhotoAlbumsCompleteCallback);
5366 }
5367 
GetAlbumFetchOption(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,bool hasCallback)5368 static napi_value GetAlbumFetchOption(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, bool hasCallback)
5369 {
5370     if (context->argc < (ARGS_ONE + hasCallback)) {
5371         NAPI_ERR_LOG("No arguments to parse");
5372         return nullptr;
5373     }
5374 
5375     // The index of fetchOption should always be the last arg besides callback
5376     napi_value fetchOption = context->argv[context->argc - 1 - hasCallback];
5377     CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, fetchOption, ALBUM_FETCH_OPT, context), JS_INNER_FAIL);
5378 
5379     napi_value result = nullptr;
5380     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5381     return result;
5382 }
5383 
ParseAlbumTypes(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context)5384 static napi_value ParseAlbumTypes(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context)
5385 {
5386     if (context->argc < ARGS_TWO) {
5387         NAPI_ERR_LOG("No arguments to parse");
5388         return nullptr;
5389     }
5390 
5391     /* Parse the first argument to photo album type */
5392     int32_t albumType;
5393     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], albumType));
5394     if (!PhotoAlbum::CheckPhotoAlbumType(static_cast<PhotoAlbumType>(albumType))) {
5395         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5396         return nullptr;
5397     }
5398     context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(albumType));
5399 
5400     /* Parse the second argument to photo album subType */
5401     int32_t albumSubType;
5402     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM1], albumSubType));
5403     if (!PhotoAlbum::CheckPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(albumSubType))) {
5404         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5405         return nullptr;
5406     }
5407     if (albumSubType != ANY) {
5408         context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(albumSubType));
5409     }
5410 
5411     napi_value result = nullptr;
5412     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5413     return result;
5414 }
5415 
ParseArgsGetPhotoAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5416 static napi_value ParseArgsGetPhotoAlbum(napi_env env, napi_callback_info info,
5417     unique_ptr<MediaLibraryAsyncContext> &context)
5418 {
5419     constexpr size_t minArgs = ARGS_ZERO;
5420     constexpr size_t maxArgs = ARGS_FOUR;
5421     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5422         JS_ERR_PARAMETER_INVALID);
5423 
5424     bool hasCallback = false;
5425     CHECK_ARGS(env, MediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback),
5426         JS_ERR_PARAMETER_INVALID);
5427     if (context->argc == ARGS_THREE) {
5428         napi_valuetype valueType = napi_undefined;
5429         if (napi_typeof(env, context->argv[PARAM2], &valueType) == napi_ok &&
5430             (valueType == napi_undefined || valueType == napi_null)) {
5431             context->argc -= 1;
5432         }
5433     }
5434     switch (context->argc - hasCallback) {
5435         case ARGS_ZERO:
5436             break;
5437         case ARGS_ONE:
5438             CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
5439             break;
5440         case ARGS_TWO:
5441             CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
5442             break;
5443         case ARGS_THREE:
5444             CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
5445             CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
5446             break;
5447         default:
5448             return nullptr;
5449     }
5450     CHECK_NULLPTR_RET(AddDefaultPhotoAlbumColumns(env, context->fetchColumn));
5451 
5452     napi_value result = nullptr;
5453     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5454     return result;
5455 }
5456 
GetPhotoAlbums(napi_env env,napi_callback_info info)5457 napi_value MediaLibraryNapi::GetPhotoAlbums(napi_env env, napi_callback_info info)
5458 {
5459     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5460     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
5461     CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
5462 
5463     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums", JSGetPhotoAlbumsExecute,
5464         JSGetPhotoAlbumsCompleteCallback);
5465 }
5466 
PhotoAccessGetPhotoAlbums(napi_env env,napi_callback_info info)5467 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbums(napi_env env, napi_callback_info info)
5468 {
5469     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5470     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5471     CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
5472 
5473     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums", JSGetPhotoAlbumsExecute,
5474         JSGetPhotoAlbumsCompleteCallback);
5475 }
5476 
CreatePositionTypeEnum(napi_env env)5477 napi_value MediaLibraryNapi::CreatePositionTypeEnum(napi_env env)
5478 {
5479     const int32_t startIdx = 1;
5480     return CreateNumberEnumProperty(env, positionTypeEnum, sPositionTypeEnumRef_, startIdx);
5481 }
5482 
CreatePhotoSubTypeEnum(napi_env env)5483 napi_value MediaLibraryNapi::CreatePhotoSubTypeEnum(napi_env env)
5484 {
5485     return CreateNumberEnumProperty(env, photoSubTypeEnum, sPhotoSubType_);
5486 }
5487 
PhotoAccessCreateAssetExecute(napi_env env,void * data)5488 static void PhotoAccessCreateAssetExecute(napi_env env, void *data)
5489 {
5490     MediaLibraryTracer tracer;
5491     tracer.Start("JSCreateAssetExecute");
5492 
5493     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5494     if (!CheckDisplayNameParams(context)) {
5495         context->error = JS_E_DISPLAYNAME;
5496         return;
5497     }
5498     if ((context->resultNapiType != ResultNapiType::TYPE_PHOTOACCESS_HELPER) && (!CheckRelativePathParams(context))) {
5499         context->error = JS_E_RELATIVEPATH;
5500         return;
5501     }
5502 
5503     string uri;
5504     GetCreateUri(context, uri);
5505     Uri createFileUri(uri);
5506     string outUri;
5507     int index = UserFileClient::InsertExt(createFileUri, context->valuesBucket, outUri);
5508     if (index < 0) {
5509         context->SaveError(index);
5510     } else {
5511         if (context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
5512             if (context->isCreateByComponent) {
5513                 context->uri = outUri;
5514             } else {
5515                 PhotoAccessSetFileAssetByIdV10(index, "", outUri, context);
5516             }
5517         } else {
5518 #ifdef MEDIALIBRARY_COMPATIBILITY
5519             SetFileAssetByIdV9(index, "", context);
5520 #else
5521             getFileAssetById(index, "", context);
5522 #endif
5523         }
5524     }
5525 }
5526 
PhotoAccessHelperCreatePhotoAsset(napi_env env,napi_callback_info info)5527 napi_value MediaLibraryNapi::PhotoAccessHelperCreatePhotoAsset(napi_env env, napi_callback_info info)
5528 {
5529     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5530     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5531     asyncContext->assetType = TYPE_PHOTO;
5532     NAPI_ASSERT(env, ParseArgsCreatePhotoAsset(env, info, asyncContext), "Failed to parse js args");
5533 
5534     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCreatePhotoAsset",
5535         PhotoAccessCreateAssetExecute, JSCreateAssetCompleteCallback);
5536 }
5537 
PhotoAccessHelperOnCallback(napi_env env,napi_callback_info info)5538 napi_value MediaLibraryNapi::PhotoAccessHelperOnCallback(napi_env env, napi_callback_info info)
5539 {
5540     MediaLibraryTracer tracer;
5541     tracer.Start("PhotoAccessHelperOnCallback");
5542     napi_value undefinedResult = nullptr;
5543     napi_get_undefined(env, &undefinedResult);
5544     size_t argc = ARGS_THREE;
5545     napi_value argv[ARGS_THREE] = {nullptr};
5546     napi_value thisVar = nullptr;
5547     GET_JS_ARGS(env, info, argc, argv, thisVar);
5548     if (argc == ARGS_TWO) {
5549         return JSOnCallback(env, info);
5550     }
5551     NAPI_ASSERT(env, argc == ARGS_THREE, "requires 3 parameters");
5552     MediaLibraryNapi *obj = nullptr;
5553     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
5554     if (status == napi_ok && obj != nullptr) {
5555         napi_valuetype valueType = napi_undefined;
5556         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
5557             napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_boolean ||
5558             napi_typeof(env, argv[PARAM2], &valueType) != napi_ok || valueType != napi_function) {
5559             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5560             return undefinedResult;
5561         }
5562         char buffer[ARG_BUF_SIZE];
5563         size_t res = 0;
5564         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
5565             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5566             return undefinedResult;
5567         }
5568         string uri = string(buffer);
5569         bool isDerived = false;
5570         if (napi_get_value_bool(env, argv[PARAM1], &isDerived) != napi_ok) {
5571             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5572             return undefinedResult;
5573         }
5574         const int32_t refCount = 1;
5575         napi_ref cbOnRef;
5576         napi_create_reference(env, argv[PARAM2], refCount, &cbOnRef);
5577         tracer.Start("RegisterNotifyChange");
5578         if (CheckRef(env, cbOnRef, *g_listObj, false, uri)) {
5579             obj->RegisterNotifyChange(env, uri, isDerived, cbOnRef, *g_listObj);
5580         } else {
5581             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5582             return undefinedResult;
5583         }
5584         tracer.Finish();
5585     }
5586     return undefinedResult;
5587 }
5588 
PhotoAccessHelperOffCallback(napi_env env,napi_callback_info info)5589 napi_value MediaLibraryNapi::PhotoAccessHelperOffCallback(napi_env env, napi_callback_info info)
5590 {
5591     MediaLibraryTracer tracer;
5592     tracer.Start("PhotoAccessHelperOffCallback");
5593     napi_value undefinedResult = nullptr;
5594     napi_get_undefined(env, &undefinedResult);
5595 
5596     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5597     napi_value thisVar = UserFileMgrOffCheckArgs(env, info, asyncContext);
5598     MediaLibraryNapi *obj = nullptr;
5599     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
5600     if (status != napi_ok || obj == nullptr || g_listObj == nullptr) {
5601         return undefinedResult;
5602     }
5603     size_t res = 0;
5604     char buffer[ARG_BUF_SIZE];
5605     if (napi_get_value_string_utf8(env, asyncContext->argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
5606         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5607         return undefinedResult;
5608     }
5609 
5610     string uri = string(buffer);
5611     napi_valuetype valueType = napi_undefined;
5612     if (ListenerTypeMaps.find(uri) != ListenerTypeMaps.end()) {
5613         if (asyncContext->argc == ARGS_TWO) {
5614             if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
5615                 return undefinedResult;
5616             }
5617             const int32_t refCount = 1;
5618             napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &g_listObj->cbOffRef_);
5619         }
5620         obj->UnregisterChange(env, uri, *g_listObj);
5621         return undefinedResult;
5622     }
5623     napi_ref cbOffRef = nullptr;
5624     if (asyncContext->argc == ARGS_TWO) {
5625         if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
5626             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5627             return undefinedResult;
5628         }
5629         const int32_t refCount = 1;
5630         napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &cbOffRef);
5631     }
5632     tracer.Start("UnRegisterNotifyChange");
5633     obj->UnRegisterNotifyChange(env, uri, cbOffRef, *g_listObj);
5634     return undefinedResult;
5635 }
5636 
ParseArgsPHAccessHelperTrash(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5637 napi_value ParseArgsPHAccessHelperTrash(napi_env env, napi_callback_info info,
5638     unique_ptr<MediaLibraryAsyncContext> &context)
5639 {
5640     vector<string> uris;
5641     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringArrayCallback(env, info, context, uris),
5642         JS_ERR_PARAMETER_INVALID);
5643     if (uris.empty()) {
5644         NapiError::ThrowError(env, JS_E_URI, "Failed to check empty uri!");
5645         return nullptr;
5646     }
5647     for (const auto &uri : uris) {
5648         if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == string::npos) {
5649             NapiError::ThrowError(env, JS_E_URI, "Failed to check uri format, not a photo uri!");
5650             return nullptr;
5651         }
5652     }
5653     context->uris = uris;
5654 
5655     napi_value result = nullptr;
5656     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5657     return result;
5658 }
5659 
PhotoAccessHelperTrashExecute(napi_env env,void * data)5660 static void PhotoAccessHelperTrashExecute(napi_env env, void *data)
5661 {
5662     MediaLibraryTracer tracer;
5663     tracer.Start("PhotoAccessHelperTrashExecute");
5664 
5665     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5666     const vector<string> &uris = context->uris;
5667     string tmpUri;
5668     vector<string> trashIds;
5669     for (const auto &uri : uris) {
5670         tmpUri = uri;
5671         MediaFileUri::RemoveAllFragment(tmpUri);
5672         string trashId = MediaFileUtils::GetIdFromUri(tmpUri);
5673         trashIds.push_back(trashId);
5674     }
5675     string trashUri = PAH_TRASH_PHOTO;
5676     MediaLibraryNapiUtils::UriAppendKeyValue(trashUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5677     Uri updateAssetUri(trashUri);
5678     DataSharePredicates predicates;
5679     predicates.In(MediaColumn::MEDIA_ID, trashIds);
5680     DataShareValuesBucket valuesBucket;
5681     valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, MediaFileUtils::UTCTimeSeconds());
5682     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
5683     if (changedRows < 0) {
5684         context->SaveError(changedRows);
5685         NAPI_ERR_LOG("Media asset delete failed, err: %{public}d", changedRows);
5686     }
5687 }
5688 
PhotoAccessHelperTrashAsset(napi_env env,napi_callback_info info)5689 napi_value MediaLibraryNapi::PhotoAccessHelperTrashAsset(napi_env env, napi_callback_info info)
5690 {
5691     napi_value ret = nullptr;
5692     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5693     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
5694     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5695     CHECK_NULLPTR_RET(ParseArgsPHAccessHelperTrash(env, info, asyncContext));
5696     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperTrashAsset",
5697         PhotoAccessHelperTrashExecute, JSTrashAssetCompleteCallback);
5698 }
5699 } // namespace Media
5700 } // namespace OHOS
5701