• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-2022 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 #define MLOG_TAG "MediaLibraryNapi"
16 
17 #include "media_library_napi.h"
18 
19 #include <fcntl.h>
20 #include <sys/sendfile.h>
21 #include "media_file_utils.h"
22 #include "hitrace_meter.h"
23 #include "medialibrary_client_errno.h"
24 #include "medialibrary_data_manager.h"
25 #include "medialibrary_db_const.h"
26 #include "medialibrary_errno.h"
27 #include "medialibrary_napi_log.h"
28 #include "medialibrary_peer_info.h"
29 #include "medialibrary_tracer.h"
30 #include "smart_album_napi.h"
31 #include "directory_ex.h"
32 #include "file_ex.h"
33 #include "uv.h"
34 #include "result_set_utils.h"
35 #include "string_ex.h"
36 #include "string_wrapper.h"
37 #include "userfile_client.h"
38 
39 using namespace std;
40 using namespace OHOS::AppExecFwk;
41 using namespace OHOS::NativeRdb;
42 using namespace OHOS::DataShare;
43 
44 namespace OHOS {
45 namespace Media {
46 thread_local unique_ptr<ChangeListenerNapi> g_listObj = nullptr;
47 const int32_t NUM_2 = 2;
48 const int32_t NUM_3 = 3;
49 const string DATE_FUNCTION = "DATE(";
50 
51 std::mutex MediaLibraryNapi::sUserFileClientMutex_;
52 
53 static map<string, ListenerType> ListenerTypeMaps = {
54     {"audioChange", AUDIO_LISTENER},
55     {"videoChange", VIDEO_LISTENER},
56     {"imageChange", IMAGE_LISTENER},
57     {"fileChange", FILE_LISTENER},
58     {"albumChange", ALBUM_LISTENER},
59     {"deviceChange", DEVICE_LISTENER},
60     {"remoteFileChange", REMOTEFILE_LISTENER}
61 };
62 
63 thread_local napi_ref MediaLibraryNapi::sConstructor_ = nullptr;
64 thread_local napi_ref MediaLibraryNapi::sMediaTypeEnumRef_ = nullptr;
65 thread_local napi_ref MediaLibraryNapi::sDirectoryEnumRef_ = nullptr;
66 thread_local napi_ref MediaLibraryNapi::sVirtualAlbumTypeEnumRef_ = nullptr;
67 thread_local napi_ref MediaLibraryNapi::sFileKeyEnumRef_ = nullptr;
68 thread_local napi_ref MediaLibraryNapi::sPrivateAlbumEnumRef_ = nullptr;
69 using CompleteCallback = napi_async_complete_callback;
70 using Context = MediaLibraryAsyncContext* ;
71 
72 thread_local napi_ref MediaLibraryNapi::userFileMgrConstructor_ = nullptr;
73 thread_local napi_ref MediaLibraryNapi::sUserFileMgrFileKeyEnumRef_ = nullptr;
74 thread_local napi_ref MediaLibraryNapi::sAudioKeyEnumRef_ = nullptr;
75 thread_local napi_ref MediaLibraryNapi::sImageVideoKeyEnumRef_ = nullptr;
76 thread_local napi_ref MediaLibraryNapi::sAlbumKeyEnumRef_ = nullptr;
77 
MediaLibraryNapi()78 MediaLibraryNapi::MediaLibraryNapi()
79     : resultNapiType_(ResultNapiType::TYPE_NAPI_MAX), env_(nullptr) {}
80 
81 MediaLibraryNapi::~MediaLibraryNapi() = default;
82 
MediaLibraryNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)83 void MediaLibraryNapi::MediaLibraryNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
84 {
85     MediaLibraryNapi *mediaLibrary = reinterpret_cast<MediaLibraryNapi*>(nativeObject);
86     if (mediaLibrary != nullptr) {
87         delete mediaLibrary;
88         mediaLibrary = nullptr;
89     }
90 }
91 
Init(napi_env env,napi_value exports)92 napi_value MediaLibraryNapi::Init(napi_env env, napi_value exports)
93 {
94     napi_property_descriptor media_library_properties[] = {
95         DECLARE_NAPI_FUNCTION("getPublicDirectory", JSGetPublicDirectory),
96         DECLARE_NAPI_FUNCTION("getFileAssets", JSGetFileAssets),
97         DECLARE_NAPI_FUNCTION("getAlbums", JSGetAlbums),
98         DECLARE_NAPI_FUNCTION("createAsset", JSCreateAsset),
99         DECLARE_NAPI_FUNCTION("deleteAsset", JSDeleteAsset),
100         DECLARE_NAPI_FUNCTION("on", JSOnCallback),
101         DECLARE_NAPI_FUNCTION("off", JSOffCallback),
102         DECLARE_NAPI_FUNCTION("release", JSRelease),
103         DECLARE_NAPI_FUNCTION("getSmartAlbums", JSGetSmartAlbums),
104         DECLARE_NAPI_FUNCTION("getPrivateAlbum", JSGetPrivateAlbum),
105         DECLARE_NAPI_FUNCTION("createSmartAlbum", JSCreateSmartAlbum),
106         DECLARE_NAPI_FUNCTION("deleteSmartAlbum", JSDeleteSmartAlbum),
107         DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
108         DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
109         DECLARE_NAPI_FUNCTION("storeMediaAsset", JSStoreMediaAsset),
110         DECLARE_NAPI_FUNCTION("startImagePreview", JSStartImagePreview),
111     };
112     napi_property_descriptor static_prop[] = {
113         DECLARE_NAPI_STATIC_FUNCTION("getMediaLibrary", GetMediaLibraryNewInstance),
114         DECLARE_NAPI_PROPERTY("MediaType", CreateMediaTypeEnum(env)),
115         DECLARE_NAPI_PROPERTY("FileKey", CreateFileKeyEnum(env)),
116         DECLARE_NAPI_PROPERTY("DirectoryType", CreateDirectoryTypeEnum(env)),
117         DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env))
118     };
119     napi_value ctorObj;
120     napi_status status = napi_define_class(env, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
121         MediaLibraryNapiConstructor, nullptr,
122         sizeof(media_library_properties) / sizeof(media_library_properties[PARAM0]),
123         media_library_properties, &ctorObj);
124     if (status == napi_ok) {
125         int32_t refCount = 1;
126         if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
127             status = napi_set_named_property(env, exports, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), ctorObj);
128             if (status == napi_ok && napi_define_properties(env, exports,
129                 sizeof(static_prop) / sizeof(static_prop[PARAM0]), static_prop) == napi_ok) {
130                 return exports;
131             }
132         }
133     }
134     return nullptr;
135 }
136 
UserFileMgrInit(napi_env env,napi_value exports)137 napi_value MediaLibraryNapi::UserFileMgrInit(napi_env env, napi_value exports)
138 {
139     NapiClassInfo info = {
140         USERFILE_MGR_NAPI_CLASS_NAME,
141         &userFileMgrConstructor_,
142         MediaLibraryNapiConstructor,
143         {
144             DECLARE_NAPI_FUNCTION("getPublicDirectory", JSGetPublicDirectory),
145             DECLARE_NAPI_FUNCTION("getPhotoAssets", UserFileMgrGetPhotoAssets),
146             DECLARE_NAPI_FUNCTION("getAudioAssets", UserFileMgrGetAudioAssets),
147             DECLARE_NAPI_FUNCTION("getPhotoAlbums", UserFileMgrGetAlbums),
148             DECLARE_NAPI_FUNCTION("createPhotoAsset", UserFileMgrCreateAsset),
149             DECLARE_NAPI_FUNCTION("delete", UserFileMgrTrashAsset),
150             DECLARE_NAPI_FUNCTION("on", JSOnCallback),
151             DECLARE_NAPI_FUNCTION("off", JSOffCallback),
152             DECLARE_NAPI_FUNCTION("getPrivateAlbum", UserFileMgrGetPrivateAlbum),
153             DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
154             DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
155             DECLARE_NAPI_FUNCTION("release", JSRelease),
156         }
157     };
158     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
159 
160     const std::vector<napi_property_descriptor> staticProps = {
161         DECLARE_NAPI_STATIC_FUNCTION("getUserFileMgr", GetUserFileMgr),
162         DECLARE_NAPI_PROPERTY("FileType", CreateMediaTypeUserFileEnum(env)),
163         DECLARE_NAPI_PROPERTY("FileKey", UserFileMgrCreateFileKeyEnum(env)),
164         DECLARE_NAPI_PROPERTY("AudioKey", CreateAudioKeyEnum(env)),
165         DECLARE_NAPI_PROPERTY("ImageVideoKey", CreateImageVideoKeyEnum(env)),
166         DECLARE_NAPI_PROPERTY("AlbumKey", CreateAlbumKeyEnum(env)),
167         DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env))
168     };
169     MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
170     return exports;
171 }
172 
173 // Constructor callback
MediaLibraryNapiConstructor(napi_env env,napi_callback_info info)174 napi_value MediaLibraryNapi::MediaLibraryNapiConstructor(napi_env env, napi_callback_info info)
175 {
176     napi_status status;
177     napi_value result = nullptr;
178     napi_value thisVar = nullptr;
179     MediaLibraryTracer tracer;
180 
181     tracer.Start("MediaLibraryNapiConstructor");
182 
183     NAPI_CALL(env, napi_get_undefined(env, &result));
184     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
185     if (status != napi_ok || thisVar == nullptr) {
186         NAPI_ERR_LOG("Error while obtaining js environment information, status: %{public}d", status);
187         return result;
188     }
189 
190     unique_ptr<MediaLibraryNapi> obj = make_unique<MediaLibraryNapi>();
191     if (obj == nullptr) {
192         return result;
193     }
194     obj->env_ = env;
195     // Initialize the ChangeListener object
196     if (g_listObj == nullptr) {
197         g_listObj = make_unique<ChangeListenerNapi>(env);
198     }
199 
200     std::unique_lock<std::mutex> helperLock(sUserFileClientMutex_);
201     if (!UserFileClient::IsValid()) {
202         UserFileClient::Init(env, info);
203         if (!UserFileClient::IsValid()) {
204             NAPI_ERR_LOG("UserFileClient creation failed");
205             napi_get_undefined(env, &(result));
206             return result;
207         }
208     }
209     helperLock.unlock();
210 
211     status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
212                        MediaLibraryNapi::MediaLibraryNapiDestructor, nullptr, nullptr);
213     if (status == napi_ok) {
214         obj.release();
215         return thisVar;
216     } else {
217         NAPI_ERR_LOG("Failed to wrap the native media lib client object with JS, status: %{public}d", status);
218     }
219 
220     return result;
221 }
222 
CreateNewInstance(napi_env env,napi_callback_info info,napi_ref ref)223 static napi_value CreateNewInstance(napi_env env, napi_callback_info info, napi_ref ref)
224 {
225     constexpr size_t ARG_CONTEXT = 1;
226     size_t argc = ARG_CONTEXT;
227     napi_value argv[ARG_CONTEXT] = {0};
228 
229     napi_value thisVar = nullptr;
230     napi_value ctor = nullptr;
231     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
232     NAPI_CALL(env, napi_get_reference_value(env, ref, &ctor));
233 
234     napi_value result = nullptr;
235     NAPI_CALL(env, napi_new_instance(env, ctor, argc, argv, &result));
236     return result;
237 }
238 
GetMediaLibraryNewInstance(napi_env env,napi_callback_info info)239 napi_value MediaLibraryNapi::GetMediaLibraryNewInstance(napi_env env, napi_callback_info info)
240 {
241     MediaLibraryTracer tracer;
242     tracer.Start("getMediaLibrary");
243 
244     napi_value result = nullptr;
245     napi_value ctor;
246     size_t argc = ARGS_ONE;
247     napi_value argv[ARGS_ONE] = {0};
248     napi_value thisVar = nullptr;
249     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
250     napi_status status = napi_get_reference_value(env, sConstructor_, &ctor);
251     if (status == napi_ok) {
252         status = napi_new_instance(env, ctor, argc, argv, &result);
253         if (status == napi_ok) {
254             return result;
255         } else {
256             NAPI_ERR_LOG("New instance could not be obtained status: %{public}d", status);
257         }
258     } else {
259             NAPI_ERR_LOG("status = %{public}d", status);
260     }
261 
262     napi_get_undefined(env, &result);
263 
264     return result;
265 }
266 
GetUserFileMgr(napi_env env,napi_callback_info info)267 napi_value MediaLibraryNapi::GetUserFileMgr(napi_env env, napi_callback_info info)
268 {
269     MediaLibraryTracer tracer;
270     tracer.Start("getUserFileManager");
271 
272     return CreateNewInstance(env, info, userFileMgrConstructor_);
273 }
274 
AddIntegerNamedProperty(napi_env env,napi_value object,const string & name,int32_t enumValue)275 static napi_status AddIntegerNamedProperty(napi_env env, napi_value object,
276     const string &name, int32_t enumValue)
277 {
278     napi_value enumNapiValue;
279     napi_status status = napi_create_int32(env, enumValue, &enumNapiValue);
280     if (status == napi_ok) {
281         status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
282     }
283     return status;
284 }
285 
CreateNumberEnumProperty(napi_env env,vector<string> properties,napi_ref & ref,int32_t offset=0)286 static napi_value CreateNumberEnumProperty(napi_env env, vector<string> properties, napi_ref &ref, int32_t offset = 0)
287 {
288     napi_value result = nullptr;
289     NAPI_CALL(env, napi_create_object(env, &result));
290     for (size_t i = 0; i < properties.size(); i++) {
291         NAPI_CALL(env, AddIntegerNamedProperty(env, result, properties[i], i + offset));
292     }
293     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
294     return result;
295 }
296 
AddStringNamedProperty(napi_env env,napi_value object,const string & name,string enumValue)297 static napi_status AddStringNamedProperty(napi_env env, napi_value object,
298     const string &name, string enumValue)
299 {
300     napi_value enumNapiValue;
301     napi_status status = napi_create_string_utf8(env, enumValue.c_str(), NAPI_AUTO_LENGTH, &enumNapiValue);
302     if (status == napi_ok) {
303         status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
304     }
305     return status;
306 }
307 
CreateStringEnumProperty(napi_env env,vector<pair<string,string>> properties,napi_ref & ref)308 static napi_value CreateStringEnumProperty(napi_env env, vector<pair<string, string>> properties, napi_ref &ref)
309 {
310     napi_value result = nullptr;
311     NAPI_CALL(env, napi_create_object(env, &result));
312     for (unsigned int i = 0; i < properties.size(); i++) {
313         NAPI_CALL(env, AddStringNamedProperty(env, result, properties[i].first, properties[i].second));
314     }
315     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
316     return result;
317 }
318 
DealWithCommonParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err,bool & present)319 static void DealWithCommonParam(napi_env env, napi_value arg,
320     const MediaLibraryAsyncContext &context, bool &err, bool &present)
321 {
322     MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
323     CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
324     char buffer[PATH_MAX];
325     size_t res = 0;
326     napi_value property = nullptr;
327     napi_has_named_property(env, arg, "selections", &present);
328     if (present) {
329         if ((napi_get_named_property(env, arg, "selections", &property) != napi_ok) ||
330             (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
331             NAPI_ERR_LOG("Could not get the string argument!");
332             err = true;
333             return;
334         } else {
335             asyncContext->selection = buffer;
336             CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
337         }
338         present = false;
339     }
340 
341     napi_has_named_property(env, arg, "order", &present);
342     if (present) {
343         if ((napi_get_named_property(env, arg, "order", &property) != napi_ok) ||
344             (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
345             NAPI_ERR_LOG("Could not get the string argument!");
346             err = true;
347             return;
348         } else {
349             asyncContext->order = buffer;
350             CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
351         }
352         present = false;
353     }
354 
355     napi_has_named_property(env, arg, "uri", &present);
356     if (present) {
357         if ((napi_get_named_property(env, arg, "uri", &property) != napi_ok)||
358             (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
359             NAPI_ERR_LOG("Could not get the uri property!");
360             err = true;
361             return;
362         }
363         asyncContext->uri = buffer;
364         CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
365         present = false;
366     }
367 
368     napi_has_named_property(env, arg, "networkId", &present);
369     if (present) {
370         if ((napi_get_named_property(env, arg, "networkId", &property) != napi_ok) ||
371             (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
372             NAPI_ERR_LOG("Could not get the networkId string argument!");
373             err = true;
374             return;
375         } else {
376             asyncContext->networkId = buffer;
377             CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
378         }
379         present = false;
380     }
381     napi_has_named_property(env, arg, "extendArgs", &present);
382     if (present) {
383         if ((napi_get_named_property(env, arg, "extendArgs", &property) != napi_ok) ||
384             (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
385             NAPI_ERR_LOG("Could not get the extendArgs string argument!");
386             err = true;
387             return;
388         } else {
389             asyncContext->extendArgs = buffer;
390             CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
391         }
392         present = false;
393     }
394 }
395 
GetFetchOptionsParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err)396 static void GetFetchOptionsParam(napi_env env, napi_value arg, const MediaLibraryAsyncContext &context, bool &err)
397 {
398     MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
399     CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
400     napi_value property = nullptr;
401     napi_value stringItem = nullptr;
402     bool present = false;
403     DealWithCommonParam(env, arg, context, err, present);
404     napi_has_named_property(env, arg, "selectionArgs", &present);
405     if (present && napi_get_named_property(env, arg, "selectionArgs", &property) == napi_ok) {
406         uint32_t len = 0;
407         napi_get_array_length(env, property, &len);
408         char buffer[PATH_MAX];
409         for (size_t i = 0; i < len; i++) {
410             napi_get_element(env, property, i, &stringItem);
411             size_t res = 0;
412             napi_get_value_string_utf8(env, stringItem, buffer, PATH_MAX, &res);
413             asyncContext->selectionArgs.push_back(string(buffer));
414             CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
415         }
416     } else {
417         NAPI_ERR_LOG("Could not get the string argument!");
418         err = true;
419     }
420 }
421 
ConvertJSArgsToNative(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)422 static napi_value ConvertJSArgsToNative(napi_env env, size_t argc, const napi_value argv[],
423     MediaLibraryAsyncContext &asyncContext)
424 {
425     bool err = false;
426     const int32_t refCount = 1;
427     auto context = &asyncContext;
428 
429     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
430     for (size_t i = PARAM0; i < argc; i++) {
431         napi_valuetype valueType = napi_undefined;
432         napi_typeof(env, argv[i], &valueType);
433 
434         if (i == PARAM0 && valueType == napi_object) {
435             GetFetchOptionsParam(env, argv[PARAM0], asyncContext, err);
436         } else if (i == PARAM0 && valueType == napi_function) {
437             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
438             break;
439         } else if (i == PARAM1 && valueType == napi_function) {
440             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
441             break;
442         } else {
443             NAPI_ASSERT(env, false, "type mismatch");
444         }
445         if (err) {
446             NAPI_ERR_LOG("fetch options retrieval failed, err: %{public}d", err);
447             NAPI_ASSERT(env, false, "type mismatch");
448         }
449     }
450 
451     // Return true napi_value if params are successfully obtained
452     napi_value result;
453     napi_get_boolean(env, true, &result);
454     return result;
455 }
456 
GetPublicDirectoryExecute(napi_env env,void * data)457 static void GetPublicDirectoryExecute(napi_env env, void *data)
458 {
459     MediaLibraryTracer tracer;
460     tracer.Start("GetPublicDirectoryExecute");
461 
462     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
463     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
464 
465     vector<string> selectionArgs;
466     vector<string> columns;
467     DataSharePredicates predicates;
468     NAPI_ERR_LOG("context->dirType is = %{public}d", context->dirType);
469     selectionArgs.push_back(to_string(context->dirType));
470     predicates.SetWhereClause(CATEGORY_MEDIATYPE_DIRECTORY_DB_DIRECTORY_TYPE + " = ?");
471     predicates.SetWhereArgs(selectionArgs);
472     string queryUri = MEDIALIBRARY_DIRECTORY_URI;
473     Uri uri(queryUri);
474 
475     shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns);
476     if (resultSet != nullptr) {
477         auto count = 0;
478         auto ret = resultSet->GetRowCount(count);
479         if (ret != NativeRdb::E_OK) {
480             NAPI_ERR_LOG("get rdbstore failed");
481             context->error = JS_INNER_FAIL;
482             return;
483         }
484         if (count == 0) {
485             NAPI_ERR_LOG("Query for get publicDirectory form db failed");
486             context->error = JS_INNER_FAIL;
487             return;
488         }
489         NAPI_ERR_LOG("Query for get publicDirectory count = %{private}d", count);
490         if (resultSet->GoToFirstRow() == NativeRdb::E_OK) {
491             context->directoryRelativePath = get<string>(
492                 ResultSetUtils::GetValFromColumn(CATEGORY_MEDIATYPE_DIRECTORY_DB_DIRECTORY, resultSet, TYPE_STRING));
493         }
494         return;
495     } else {
496         context->SaveError(resultSet);
497         NAPI_ERR_LOG("Query for get publicDirectory failed");
498     }
499 }
500 
GetPublicDirectoryCallbackComplete(napi_env env,napi_status status,void * data)501 static void GetPublicDirectoryCallbackComplete(napi_env env, napi_status status, void *data)
502 {
503     MediaLibraryTracer tracer;
504     tracer.Start("GetPublicDirectoryCallbackComplete");
505 
506     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
507     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
508     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
509     jsContext->status = false;
510     if (context->error == ERR_DEFAULT) {
511         napi_create_string_utf8(env, context->directoryRelativePath.c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
512         jsContext->status = true;
513         napi_get_undefined(env, &jsContext->error);
514     } else {
515         context->HandleError(env, jsContext->error);
516         napi_get_undefined(env, &jsContext->data);
517     }
518 
519     tracer.Finish();
520     if (context->work != nullptr) {
521         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
522                                                    context->work, *jsContext);
523     }
524 
525     delete context;
526 }
527 
JSGetPublicDirectory(napi_env env,napi_callback_info info)528 napi_value MediaLibraryNapi::JSGetPublicDirectory(napi_env env, napi_callback_info info)
529 {
530     napi_status status;
531     napi_value result = nullptr;
532     size_t argc = ARGS_TWO;
533     napi_value argv[ARGS_TWO] = {0};
534     napi_value thisVar = nullptr;
535     const int32_t refCount = 1;
536 
537     MediaLibraryTracer tracer;
538     tracer.Start("JSGetPublicDirectory");
539 
540     GET_JS_ARGS(env, info, argc, argv, thisVar);
541     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
542     napi_get_undefined(env, &result);
543 
544     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
545     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
546     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
547         for (size_t i = PARAM0; i < argc; i++) {
548             napi_valuetype valueType = napi_undefined;
549             napi_typeof(env, argv[i], &valueType);
550 
551             if (i == PARAM0 && valueType == napi_number) {
552                 napi_get_value_uint32(env, argv[i], &asyncContext->dirType);
553             } else if (i == PARAM1 && valueType == napi_function) {
554                 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
555                 break;
556             } else {
557                 NAPI_ASSERT(env, false, "type mismatch");
558             }
559         }
560         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPublicDirectory",
561             GetPublicDirectoryExecute, GetPublicDirectoryCallbackComplete);
562     }
563 
564     return result;
565 }
566 
GetFileAssetUpdatePredicates(MediaLibraryAsyncContext * context)567 static void GetFileAssetUpdatePredicates(MediaLibraryAsyncContext *context)
568 {
569     context->predicates.NotEqualTo(MEDIA_DATA_DB_MEDIA_TYPE, MEDIA_TYPE_ALBUM);
570     context->predicates.EqualTo(MEDIA_DATA_DB_DATE_TRASHED, 0);
571     MediaLibraryNapiUtils::UpdateMediaTypeSelections(context);
572     if (!context->uri.empty()) {
573         NAPI_ERR_LOG("context->uri is = %{public}s", context->uri.c_str());
574         string fileId;
575         MediaLibraryNapiUtils::GetNetworkIdAndFileIdFromUri(context->uri, context->networkId, fileId);
576         if (!fileId.empty()) {
577             context->predicates.EqualTo(MEDIA_DATA_DB_ID, fileId);
578         }
579     }
580 }
581 
GetFileAssetUpdateSelections(MediaLibraryAsyncContext * context)582 static void GetFileAssetUpdateSelections(MediaLibraryAsyncContext *context)
583 {
584     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
585         GetFileAssetUpdatePredicates(context);
586         return;
587     }
588 
589     string trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? ";
590     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
591     context->selectionArgs.emplace_back("0");
592 
593     string prefix = MEDIA_DATA_DB_MEDIA_TYPE + " <> ? ";
594     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, prefix);
595     context->selectionArgs.emplace_back(to_string(MEDIA_TYPE_ALBUM));
596 
597     if (!context->uri.empty()) {
598         NAPI_ERR_LOG("context->uri is = %{public}s", context->uri.c_str());
599         context->networkId = MediaLibraryDataManagerUtils::GetNetworkIdFromUri(context->uri);
600         string fileId = MediaLibraryDataManagerUtils::GetIdFromUri(context->uri);
601         if (!fileId.empty()) {
602             string idPrefix = MEDIA_DATA_DB_ID + " = ? ";
603             MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, idPrefix);
604             context->selectionArgs.emplace_back(fileId);
605         }
606     }
607 }
608 
GetFileAssetsExecute(napi_env env,void * data)609 static void GetFileAssetsExecute(napi_env env, void *data)
610 {
611     MediaLibraryTracer tracer;
612     tracer.Start("GetFileAssetsExecute");
613 
614     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
615     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
616 
617     GetFileAssetUpdateSelections(context);
618 
619     // fetch columns from fileAsset in medialibrary.d.ts
620     static const vector<string> FILE_ASSET_COLUMNS = {
621         MEDIA_DATA_DB_ID, MEDIA_DATA_DB_URI, MEDIA_DATA_DB_MIME_TYPE, MEDIA_DATA_DB_MEDIA_TYPE, MEDIA_DATA_DB_NAME,
622         MEDIA_DATA_DB_TITLE, MEDIA_DATA_DB_RELATIVE_PATH, MEDIA_DATA_DB_PARENT_ID, MEDIA_DATA_DB_SIZE,
623         MEDIA_DATA_DB_DATE_ADDED, MEDIA_DATA_DB_DATE_MODIFIED, MEDIA_DATA_DB_DATE_TAKEN, MEDIA_DATA_DB_ARTIST,
624         MEDIA_DATA_DB_WIDTH, MEDIA_DATA_DB_HEIGHT, MEDIA_DATA_DB_ORIENTATION, MEDIA_DATA_DB_DURATION,
625         MEDIA_DATA_DB_BUCKET_ID, MEDIA_DATA_DB_BUCKET_NAME, MEDIA_DATA_DB_IS_TRASH, MEDIA_DATA_DB_IS_FAV
626     };
627     if (context->fetchColumn.size() == 0) {
628         context->fetchColumn = FILE_ASSET_COLUMNS;
629     }
630 
631     if (context->extendArgs.find(DATE_FUNCTION) != string::npos) {
632         string group(" GROUP BY (");
633         group += context->extendArgs + " )";
634         context->selection += group;
635         context->fetchColumn.insert(context->fetchColumn.begin(), "count(*)");
636     }
637 
638     context->predicates.SetWhereClause(context->selection);
639     context->predicates.SetWhereArgs(context->selectionArgs);
640     context->predicates.SetOrder(context->order);
641 
642     string queryUri = MEDIALIBRARY_DATA_URI;
643     if (!context->networkId.empty()) {
644         queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
645     }
646     MediaLibraryNapiUtils::UriAddFragmentTypeMask(queryUri, context->typeMask);
647     NAPI_DEBUG_LOG("queryUri is = %{public}s", queryUri.c_str());
648     Uri uri(queryUri);
649     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
650         context->predicates, context->fetchColumn);
651     if (resultSet != nullptr) {
652         // Create FetchResult object using the contents of resultSet
653         context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
654         context->fetchFileResult->SetNetworkId(context->networkId);
655         if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
656             context->fetchFileResult->resultNapiType_ = context->resultNapiType;
657         }
658         return;
659     } else {
660         context->SaveError(resultSet);
661         NAPI_ERR_LOG("Query for get fileAssets failed");
662     }
663 }
664 
GetNapiFileResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)665 static void GetNapiFileResult(napi_env env, MediaLibraryAsyncContext *context,
666     unique_ptr<JSAsyncContextOutput> &jsContext)
667 {
668     // Create FetchResult object using the contents of resultSet
669     if (context->fetchFileResult == nullptr) {
670         NAPI_ERR_LOG("No fetch file result found!");
671         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
672             "Failed to obtain Fetch File Result");
673         return;
674     }
675     if (context->fetchFileResult->GetCount() < 0) {
676         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
677                                                      "find no data by options");
678         return;
679     }
680     napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchFileResult));
681     if (fileResult == nullptr) {
682         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
683             "Failed to create js object for Fetch File Result");
684     } else {
685         jsContext->data = fileResult;
686         jsContext->status = true;
687         napi_get_undefined(env, &jsContext->error);
688     }
689 }
690 
GetFileAssetsAsyncCallbackComplete(napi_env env,napi_status status,void * data)691 static void GetFileAssetsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
692 {
693     MediaLibraryTracer tracer;
694     tracer.Start("GetFileAssetsAsyncCallbackComplete");
695 
696     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
697     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
698 
699     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
700     jsContext->status = false;
701     napi_get_undefined(env, &jsContext->data);
702 
703     if (context->error != ERR_DEFAULT) {
704         context->HandleError(env, jsContext->error);
705     } else {
706         GetNapiFileResult(env, context, jsContext);
707     }
708 
709     tracer.Finish();
710     if (context->work != nullptr) {
711         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
712                                                    context->work, *jsContext);
713     }
714     delete context;
715 }
716 
JSGetFileAssets(napi_env env,napi_callback_info info)717 napi_value MediaLibraryNapi::JSGetFileAssets(napi_env env, napi_callback_info info)
718 {
719     napi_status status;
720     napi_value result = nullptr;
721     size_t argc = ARGS_TWO;
722     napi_value argv[ARGS_TWO] = {0};
723     napi_value thisVar = nullptr;
724 
725     MediaLibraryTracer tracer;
726     tracer.Start("JSGetFileAssets");
727 
728     GET_JS_ARGS(env, info, argc, argv, thisVar);
729     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
730     napi_get_undefined(env, &result);
731 
732     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
733     asyncContext->mediaTypes.clear();
734     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
735     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
736     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
737         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
738         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
739 
740         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetFileAssets", GetFileAssetsExecute,
741             GetFileAssetsAsyncCallbackComplete);
742     }
743 
744     return result;
745 }
746 
GetFileMediaTypeUri(MediaType mediaType,const string & networkId)747 static string GetFileMediaTypeUri(MediaType mediaType, const string &networkId)
748 {
749     string uri = MEDIALIBRARY_DATA_ABILITY_PREFIX + networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
750     switch (mediaType) {
751         case MEDIA_TYPE_AUDIO:
752             return uri + MEDIALIBRARY_TYPE_AUDIO_URI;
753             break;
754         case MEDIA_TYPE_VIDEO:
755             return uri + MEDIALIBRARY_TYPE_VIDEO_URI;
756             break;
757         case MEDIA_TYPE_IMAGE:
758             return uri + MEDIALIBRARY_TYPE_IMAGE_URI;
759             break;
760         case MEDIA_TYPE_ALBUM:
761             return uri + MEDIALIBRARY_TYPE_ALBUM_URI;
762             break;
763         case MEDIA_TYPE_SMARTALBUM:
764             return uri + MEDIALIBRARY_TYPE_SMART_URI;
765             break;
766         case MEDIA_TYPE_FILE:
767         default:
768             return uri + MEDIALIBRARY_TYPE_FILE_URI;
769             break;
770     }
771 }
772 
SetAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<AlbumAsset> & album)773 static void SetAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<AlbumAsset> &album)
774 {
775     MediaLibraryTracer tracer;
776     tracer.Start("SetAlbumCoverUri");
777     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
778     DataShare::DataSharePredicates predicates;
779     predicates.SetWhereClause(MEDIA_DATA_DB_BUCKET_ID + " = ? ");
780     predicates.SetWhereArgs({ std::to_string(album->GetAlbumId()) });
781     predicates.SetOrder(MEDIA_DATA_DB_DATE_ADDED + " DESC");
782     vector<string> columns;
783     string queryUri = MEDIALIBRARY_DATA_URI;
784     if (!context->networkId.empty()) {
785         queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
786         NAPI_DEBUG_LOG("querycoverUri is = %{public}s", queryUri.c_str());
787     }
788     Uri uri(queryUri);
789     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
790         uri, predicates, columns);
791     unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
792     fetchFileResult->SetNetworkId(context->networkId);
793     unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
794     CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetAlbumCoverUr:FileAsset is nullptr");
795     string coverUri = fileAsset->GetUri();
796     album->SetCoverUri(coverUri);
797     NAPI_DEBUG_LOG("coverUri is = %{public}s", album->GetCoverUri().c_str());
798 }
799 
SetAlbumData(AlbumAsset * albumData,shared_ptr<DataShare::DataShareResultSet> resultSet,const string & networkId)800 void SetAlbumData(AlbumAsset* albumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
801     const string &networkId)
802 {
803     // Get album id index and value
804     albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_BUCKET_ID, resultSet,
805         TYPE_INT32)));
806 
807     // Get album title index and value
808     albumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_TITLE, resultSet,
809         TYPE_STRING)));
810 
811     // Get album asset count index and value
812     albumData->SetCount(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_COUNT, resultSet, TYPE_INT32)));
813     albumData->SetAlbumUri(GetFileMediaTypeUri(MEDIA_TYPE_ALBUM, networkId) +
814         "/" + to_string(albumData->GetAlbumId()));
815     // Get album relativePath index and value
816     albumData->SetAlbumRelativePath(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_RELATIVE_PATH,
817         resultSet, TYPE_STRING)));
818     albumData->SetAlbumDateModified(get<int64_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_DATE_MODIFIED,
819         resultSet, TYPE_INT64)));
820 }
821 
GetAlbumResult(MediaLibraryAsyncContext * context,shared_ptr<DataShareResultSet> resultSet)822 static void GetAlbumResult(MediaLibraryAsyncContext *context, shared_ptr<DataShareResultSet> resultSet)
823 {
824     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
825         context->fetchAlbumResult = make_unique<FetchResult<AlbumAsset>>(move(resultSet));
826         context->fetchAlbumResult->SetNetworkId(context->networkId);
827         context->fetchAlbumResult->resultNapiType_ = context->resultNapiType;
828         context->fetchAlbumResult->typeMask_ = context->typeMask;
829         return;
830     }
831 
832     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
833         unique_ptr<AlbumAsset> albumData = make_unique<AlbumAsset>();
834         if (albumData != nullptr) {
835             SetAlbumData(albumData.get(), resultSet, context->networkId);
836             SetAlbumCoverUri(context, albumData);
837             albumData->SetAlbumTypeMask(context->typeMask);
838             context->albumNativeArray.push_back(move(albumData));
839         } else {
840             context->SaveError(E_NO_MEMORY);
841         }
842     }
843 }
844 
GetResultDataExecute(napi_env env,void * data)845 static void GetResultDataExecute(napi_env env, void *data)
846 {
847     MediaLibraryTracer tracer;
848     tracer.Start("GetResultDataExecute");
849 
850     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
851     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
852 
853     MediaLibraryNapiUtils::UpdateMediaTypeSelections(context);
854     context->predicates.SetWhereClause(context->selection);
855     context->predicates.SetWhereArgs(context->selectionArgs);
856     if (!context->order.empty()) {
857         context->predicates.SetOrder(context->order);
858     }
859 
860     vector<string> columns;
861     string queryUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
862     if (!context->networkId.empty()) {
863         queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId +
864             MEDIALIBRARY_DATA_URI_IDENTIFIER + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
865         NAPI_DEBUG_LOG("queryAlbumUri is = %{public}s", queryUri.c_str());
866     }
867     MediaLibraryNapiUtils::UriAddFragmentTypeMask(queryUri, context->typeMask);
868     Uri uri(queryUri);
869     shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, context->predicates, columns);
870 
871     if (resultSet == nullptr) {
872         NAPI_ERR_LOG("GetMediaResultData resultSet is nullptr");
873         context->SaveError(resultSet);
874         return;
875     }
876 
877     GetAlbumResult(context, resultSet);
878 }
879 
MediaLibAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)880 static void MediaLibAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
881     unique_ptr<JSAsyncContextOutput> &jsContext)
882 {
883     if (context->albumNativeArray.empty()) {
884         napi_value albumNoArray = nullptr;
885         napi_create_array(env, &albumNoArray);
886         jsContext->status = true;
887         napi_get_undefined(env, &jsContext->error);
888         jsContext->data = albumNoArray;
889     } else {
890         napi_value albumArray = nullptr;
891         napi_create_array_with_length(env, context->albumNativeArray.size(), &albumArray);
892         for (size_t i = 0; i < context->albumNativeArray.size(); i++) {
893             napi_value albumNapiObj = AlbumNapi::CreateAlbumNapi(env, context->albumNativeArray[i]);
894             napi_set_element(env, albumArray, i, albumNapiObj);
895         }
896         jsContext->status = true;
897         napi_get_undefined(env, &jsContext->error);
898         jsContext->data = albumArray;
899     }
900 }
901 
UserFileMgrAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)902 static void UserFileMgrAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
903     unique_ptr<JSAsyncContextOutput> &jsContext)
904 {
905     if (context->fetchAlbumResult->GetCount() < 0) {
906         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
907             "find no data by options");
908     } else {
909         napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchAlbumResult));
910         if (fileResult == nullptr) {
911             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
912                 "Failed to create js object for Fetch Album Result");
913         } else {
914             jsContext->data = fileResult;
915             jsContext->status = true;
916             napi_get_undefined(env, &jsContext->error);
917         }
918     }
919 }
920 
AlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)921 static void AlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
922     unique_ptr<JSAsyncContextOutput> &jsContext)
923 {
924     if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
925         MediaLibAlbumsAsyncResult(env, context, jsContext);
926     } else {
927         UserFileMgrAlbumsAsyncResult(env, context, jsContext);
928     }
929 }
930 
AlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)931 static void AlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
932 {
933     MediaLibraryTracer tracer;
934     tracer.Start("AlbumsAsyncCallbackComplete");
935 
936     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
937     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
938     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
939     jsContext->status = false;
940     napi_get_undefined(env, &jsContext->error);
941     if (context->error != ERR_DEFAULT) {
942         napi_get_undefined(env, &jsContext->data);
943         context->HandleError(env, jsContext->error);
944     } else {
945         AlbumsAsyncResult(env, context, jsContext);
946     }
947 
948     tracer.Finish();
949     if (context->work != nullptr) {
950         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
951                                                    context->work, *jsContext);
952     }
953     delete context;
954 }
955 
JSGetAlbums(napi_env env,napi_callback_info info)956 napi_value MediaLibraryNapi::JSGetAlbums(napi_env env, napi_callback_info info)
957 {
958     napi_status status;
959     napi_value result = nullptr;
960     size_t argc = ARGS_TWO;
961     napi_value argv[ARGS_TWO] = {0};
962     napi_value thisVar = nullptr;
963 
964     MediaLibraryTracer tracer;
965     tracer.Start("JSGetAlbums");
966 
967     GET_JS_ARGS(env, info, argc, argv, thisVar);
968     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
969     napi_get_undefined(env, &result);
970 
971     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
972     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
973     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
974         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
975         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
976 
977         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetAlbums", GetResultDataExecute,
978             AlbumsAsyncCallbackComplete);
979     }
980 
981     return result;
982 }
983 
getFileAssetById(int32_t id,const string & networkId,MediaLibraryAsyncContext * context)984 static void getFileAssetById(int32_t id, const string &networkId, MediaLibraryAsyncContext *context)
985 {
986     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
987     vector<string> columns;
988     DataShare::DataSharePredicates predicates;
989 
990     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
991     predicates.SetWhereArgs({ std::to_string(id) });
992 
993     string queryUri = MEDIALIBRARY_DATA_URI;
994     MediaLibraryNapiUtils::UriAddFragmentTypeMask(queryUri, context->typeMask);
995     Uri uri(queryUri);
996 
997     auto resultSet = UserFileClient::Query(uri, predicates, columns);
998     CHECK_NULL_PTR_RETURN_VOID(resultSet, "Failed to get file asset by id, query resultSet is nullptr");
999 
1000     // Create FetchResult object using the contents of resultSet
1001     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1002     CHECK_NULL_PTR_RETURN_VOID(context->fetchFileResult, "Failed to get file asset by id, fetchFileResult is nullptr");
1003     context->fetchFileResult->SetNetworkId(networkId);
1004     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
1005         context->fetchFileResult->resultNapiType_ = context->resultNapiType;
1006     }
1007     if (context->fetchFileResult->GetCount() < 1) {
1008         NAPI_ERR_LOG("Failed to query file by id: %{public}d, query count is 0", id);
1009         return;
1010     }
1011     unique_ptr<FileAsset> fileAsset = context->fetchFileResult->GetFirstObject();
1012     CHECK_NULL_PTR_RETURN_VOID(fileAsset, "getFileAssetById: fileAsset is nullptr");
1013     context->fileAsset = std::move(fileAsset);
1014 }
1015 
JSCreateAssetCompleteCallback(napi_env env,napi_status status,void * data)1016 static void JSCreateAssetCompleteCallback(napi_env env, napi_status status, void *data)
1017 {
1018     MediaLibraryTracer tracer;
1019     tracer.Start("JSCreateAssetCompleteCallback");
1020 
1021     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1022     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1023 
1024     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1025     jsContext->status = false;
1026     napi_value jsFileAsset = nullptr;
1027 
1028     if (context->error == ERR_DEFAULT) {
1029         if (context->fileAsset == nullptr) {
1030             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1031                 "Obtain file asset failed");
1032             napi_get_undefined(env, &jsContext->data);
1033         } else {
1034             jsFileAsset = FileAssetNapi::CreateFileAsset(env, context->fileAsset);
1035             if (jsFileAsset == nullptr) {
1036                 NAPI_ERR_LOG("Failed to get file asset napi object");
1037                 napi_get_undefined(env, &jsContext->data);
1038                 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1039                     "Failed to create js object for FileAsset");
1040             } else {
1041                 NAPI_DEBUG_LOG("JSCreateAssetCompleteCallback jsFileAsset != nullptr");
1042                 jsContext->data = jsFileAsset;
1043                 napi_get_undefined(env, &jsContext->error);
1044                 jsContext->status = true;
1045             }
1046         }
1047     } else {
1048         context->HandleError(env, jsContext->error);
1049         napi_get_undefined(env, &jsContext->data);
1050     }
1051 
1052     tracer.Finish();
1053     if (context->work != nullptr) {
1054         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1055                                                    context->work, *jsContext);
1056     }
1057 
1058     NAPI_DEBUG_LOG("JSCreateAssetCompleteCallback OUT");
1059     delete context;
1060 }
1061 
CheckTitlePrams(MediaLibraryAsyncContext * context)1062 static bool CheckTitlePrams(MediaLibraryAsyncContext *context)
1063 {
1064     if (context == nullptr) {
1065         NAPI_ERR_LOG("Async context is null");
1066         return false;
1067     }
1068     bool isValid = false;
1069     string title = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1070     if (!isValid) {
1071         NAPI_ERR_LOG("getting title is invalid");
1072         return false;
1073     }
1074     if (title.empty()) {
1075         return false;
1076     }
1077     return true;
1078 }
1079 
GetFirstDirName(const string & relativePath)1080 static string GetFirstDirName(const string &relativePath)
1081 {
1082     string firstDirName = "";
1083     if (!relativePath.empty()) {
1084         string::size_type pos = relativePath.find_first_of('/');
1085         if (pos == relativePath.length()) {
1086             return relativePath;
1087         }
1088         firstDirName = relativePath.substr(0, pos + 1);
1089         NAPI_DEBUG_LOG("firstDirName substr = %{private}s", firstDirName.c_str());
1090     }
1091     return firstDirName;
1092 }
1093 
IsDirectory(const string & dirName)1094 static bool IsDirectory(const string &dirName)
1095 {
1096     struct stat statInfo {};
1097     if (stat((ROOT_MEDIA_DIR + dirName).c_str(), &statInfo) == SUCCESS) {
1098         if (statInfo.st_mode & S_IFDIR) {
1099             return true;
1100         }
1101     }
1102 
1103     return false;
1104 }
1105 
CheckTypeOfType(const std::string & firstDirName,int32_t fileMediaType)1106 static bool CheckTypeOfType(const std::string &firstDirName, int32_t fileMediaType)
1107 {
1108     // "CDSA/"
1109     if (!strcmp(firstDirName.c_str(), directoryEnumValues[0].c_str())) {
1110         if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
1111             return true;
1112         } else {
1113             return false;
1114         }
1115     }
1116     // "Movies/"
1117     if (!strcmp(firstDirName.c_str(), directoryEnumValues[1].c_str())) {
1118         if (fileMediaType == MEDIA_TYPE_VIDEO) {
1119             return true;
1120         } else {
1121             return false;
1122         }
1123     }
1124     if (!strcmp(firstDirName.c_str(), directoryEnumValues[NUM_2].c_str())) {
1125         if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
1126             return true;
1127         } else {
1128             NAPI_INFO_LOG("CheckTypeOfType RETURN FALSE");
1129             return false;
1130         }
1131     }
1132     if (!strcmp(firstDirName.c_str(), directoryEnumValues[NUM_3].c_str())) {
1133         if (fileMediaType == MEDIA_TYPE_AUDIO) {
1134             return true;
1135         } else {
1136             return false;
1137         }
1138     }
1139     return true;
1140 }
CheckRelativePathPrams(MediaLibraryAsyncContext * context)1141 static bool CheckRelativePathPrams(MediaLibraryAsyncContext *context)
1142 {
1143     if (context == nullptr) {
1144         NAPI_ERR_LOG("Async context is null");
1145         return false;
1146     }
1147     bool isValid = false;
1148     string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1149     if (!isValid) {
1150         NAPI_DEBUG_LOG("getting relativePath is invalid");
1151         return false;
1152     }
1153     isValid = false;
1154     int32_t fileMediaType = context->valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
1155     if (!isValid) {
1156         NAPI_DEBUG_LOG("getting fileMediaType is invalid");
1157         return false;
1158     }
1159     if (relativePath.empty()) {
1160         NAPI_DEBUG_LOG("CheckRelativePathPrams relativePath is empty");
1161         return false;
1162     }
1163 
1164     if (IsDirectory(relativePath)) {
1165         NAPI_DEBUG_LOG("CheckRelativePathPrams relativePath exist return true");
1166         return true;
1167     }
1168 
1169     string firstDirName = GetFirstDirName(relativePath);
1170     if (!firstDirName.empty() && IsDirectory(firstDirName)) {
1171         NAPI_DEBUG_LOG("CheckRelativePathPrams firstDirName exist return true");
1172         return true;
1173     }
1174 
1175     if (!firstDirName.empty()) {
1176         NAPI_DEBUG_LOG("firstDirName = %{private}s", firstDirName.c_str());
1177         for (unsigned int i = 0; i < directoryEnumValues.size(); i++) {
1178             NAPI_DEBUG_LOG("directoryEnumValues%{public}d = %{public}s", i, directoryEnumValues[i].c_str());
1179             if (!strcmp(firstDirName.c_str(), directoryEnumValues[i].c_str())) {
1180                 return CheckTypeOfType(firstDirName, fileMediaType);
1181             }
1182         }
1183         NAPI_DEBUG_LOG("firstDirName = %{private}s", firstDirName.c_str());
1184     }
1185     NAPI_DEBUG_LOG("CheckRelativePathPrams return false");
1186     return false;
1187 }
1188 
GetJSArgsForCreateAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)1189 napi_value GetJSArgsForCreateAsset(napi_env env, size_t argc, const napi_value argv[],
1190                                    MediaLibraryAsyncContext &asyncContext)
1191 {
1192     const int32_t refCount = 1;
1193     napi_value result = nullptr;
1194     auto context = &asyncContext;
1195     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1196     int32_t fileMediaType = 0;
1197     size_t res = 0;
1198     char relativePathBuffer[PATH_MAX];
1199     char titleBuffer[PATH_MAX];
1200     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1201 
1202     for (size_t i = PARAM0; i < argc; i++) {
1203         napi_valuetype valueType = napi_undefined;
1204         napi_typeof(env, argv[i], &valueType);
1205         if (i == PARAM0 && valueType == napi_number) {
1206             napi_get_value_int32(env, argv[i], &fileMediaType);
1207         } else if (i == PARAM1 && valueType == napi_string) {
1208             napi_get_value_string_utf8(env, argv[i], titleBuffer, PATH_MAX, &res);
1209             NAPI_DEBUG_LOG("displayName = %{private}s", string(titleBuffer).c_str());
1210         } else if (i == PARAM2 && valueType == napi_string) {
1211             napi_get_value_string_utf8(env, argv[i], relativePathBuffer, PATH_MAX, &res);
1212             NAPI_DEBUG_LOG("relativePath = %{private}s", string(relativePathBuffer).c_str());
1213         } else if (i == PARAM3 && valueType == napi_function) {
1214             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1215         } else {
1216             NAPI_DEBUG_LOG("type mismatch, valueType: %{public}d", valueType);
1217             return result;
1218     }
1219     }
1220 
1221     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileMediaType);
1222     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, string(titleBuffer));
1223     context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, string(relativePathBuffer));
1224     NAPI_DEBUG_LOG("GetJSArgsForCreateAsset END");
1225     // Return true napi_value if params are successfully obtained
1226     napi_get_boolean(env, true, &result);
1227     return result;
1228 }
1229 
JSCreateAssetExecute(napi_env env,void * data)1230 static void JSCreateAssetExecute(napi_env env, void *data)
1231 {
1232     MediaLibraryTracer tracer;
1233     tracer.Start("JSCreateAssetExecute");
1234 
1235     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1236     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1237 
1238     if (!CheckTitlePrams(context)) {
1239         context->error = JS_E_DISPLAYNAME;
1240         return;
1241     }
1242     if ((context->resultNapiType != ResultNapiType::TYPE_USERFILE_MGR) && (!CheckRelativePathPrams(context))) {
1243         context->error = JS_E_RELATIVEPATH;
1244         return;
1245     }
1246     string uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1247     MediaLibraryNapiUtils::UriAddFragmentTypeMask(uri, context->typeMask);
1248     Uri createFileUri(uri);
1249     int index = UserFileClient::Insert(createFileUri, context->valuesBucket);
1250     if (index < 0) {
1251         context->SaveError(index);
1252     } else {
1253         getFileAssetById(index, "", context);
1254     }
1255 }
1256 
JSCreateAsset(napi_env env,napi_callback_info info)1257 napi_value MediaLibraryNapi::JSCreateAsset(napi_env env, napi_callback_info info)
1258 {
1259     napi_status status;
1260     napi_value result = nullptr;
1261     size_t argc = ARGS_FOUR;
1262     napi_value argv[ARGS_FOUR] = {0};
1263     napi_value thisVar = nullptr;
1264 
1265     MediaLibraryTracer tracer;
1266     tracer.Start("JSCreateAsset");
1267 
1268     GET_JS_ARGS(env, info, argc, argv, thisVar);
1269     NAPI_ASSERT(env, (argc == ARGS_THREE || argc == ARGS_FOUR), "requires 4 parameters maximum");
1270     napi_get_undefined(env, &result);
1271 
1272     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1273     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
1274     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
1275     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1276         result = GetJSArgsForCreateAsset(env, argc, argv, *asyncContext);
1277         ASSERT_NULLPTR_CHECK(env, result);
1278 
1279         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCreateAsset", JSCreateAssetExecute,
1280             JSCreateAssetCompleteCallback);
1281     }
1282 
1283     return result;
1284 }
1285 
JSDeleteAssetExecute(napi_env env,void * data)1286 static void JSDeleteAssetExecute(napi_env env, void *data)
1287 {
1288     MediaLibraryTracer tracer;
1289     tracer.Start("JSDeleteAssetExecute");
1290 
1291     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1292     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1293 
1294     string mediaType;
1295     string deleteId;
1296     bool isValid = false;
1297     string notifyUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
1298     if (!isValid) {
1299         context->error = ERR_INVALID_OUTPUT;
1300         return;
1301     }
1302     size_t index = notifyUri.rfind('/');
1303     if (index != string::npos) {
1304         deleteId = notifyUri.substr(index + 1);
1305         notifyUri = notifyUri.substr(0, index);
1306         size_t indexType = notifyUri.rfind('/');
1307         if (indexType != string::npos) {
1308             mediaType = notifyUri.substr(indexType + 1);
1309         }
1310     }
1311     notifyUri = MEDIALIBRARY_DATA_URI + "/" + mediaType;
1312     NAPI_DEBUG_LOG("JSDeleteAssetExcute notifyUri = %{public}s", notifyUri.c_str());
1313     string deleteUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_DELETEASSET + "/" + deleteId;
1314     MediaLibraryNapiUtils::UriAddFragmentTypeMask(deleteUri, context->typeMask);
1315     Uri deleteAssetUri(deleteUri);
1316     int retVal = UserFileClient::Delete(deleteAssetUri, {});
1317     if (retVal < 0) {
1318         context->SaveError(retVal);
1319     } else {
1320         context->retVal = retVal;
1321         Uri deleteNotify(notifyUri);
1322         UserFileClient::NotifyChange(deleteNotify);
1323     }
1324 }
1325 
JSDeleteAssetCompleteCallback(napi_env env,napi_status status,void * data)1326 static void JSDeleteAssetCompleteCallback(napi_env env, napi_status status, void *data)
1327 {
1328     MediaLibraryTracer tracer;
1329     tracer.Start("JSDeleteAssetCompleteCallback");
1330 
1331     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1332     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1333     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1334     jsContext->status = false;
1335 
1336     if (context->error == ERR_DEFAULT) {
1337         NAPI_DEBUG_LOG("Delete result = %{public}d", context->retVal);
1338         napi_create_int32(env, context->retVal, &jsContext->data);
1339         napi_get_undefined(env, &jsContext->error);
1340         jsContext->status = true;
1341     } else {
1342         context->HandleError(env, jsContext->error);
1343         napi_get_undefined(env, &jsContext->data);
1344     }
1345 
1346     tracer.Finish();
1347     if (context->work != nullptr) {
1348         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1349                                                    context->work, *jsContext);
1350     }
1351 
1352     delete context;
1353 }
1354 
JSTrashAssetExecute(napi_env env,void * data)1355 static void JSTrashAssetExecute(napi_env env, void *data)
1356 {
1357     MediaLibraryTracer tracer;
1358     tracer.Start("JSTrashAssetExecute");
1359 
1360     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1361     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1362 
1363     string uri = context->uri;
1364     if (uri.empty()) {
1365         context->error = ERR_INVALID_OUTPUT;
1366         return;
1367     }
1368     MediaLibraryNapiUtils::UriRemoveAllFragment(uri);
1369     string trashId = MediaLibraryDataManagerUtils::GetIdFromUri(uri);
1370 
1371     DataShareValuesBucket valuesBucket;
1372     valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, TRASH_ALBUM_ID_VALUES);
1373     valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ASSET_ID, stoi(trashId));
1374     string trashUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMMAPOPRN + "/" +
1375         MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM;
1376     MediaLibraryNapiUtils::UriAddFragmentTypeMask(trashUri, context->typeMask);
1377     Uri trashAssetUri(trashUri);
1378     int retVal = UserFileClient::Insert(trashAssetUri, valuesBucket);
1379     context->SaveError(retVal);
1380 }
1381 
JSTrashAssetCompleteCallback(napi_env env,napi_status status,void * data)1382 static void JSTrashAssetCompleteCallback(napi_env env, napi_status status, void *data)
1383 {
1384     MediaLibraryTracer tracer;
1385     tracer.Start("JSTrashAssetCompleteCallback");
1386 
1387     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1388     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1389     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1390     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
1391     jsContext->status = false;
1392     napi_get_undefined(env, &jsContext->data);
1393     if (context->error == ERR_DEFAULT) {
1394         jsContext->status = true;
1395         Media::MediaType mediaType = MediaLibraryNapiUtils::GetMediaTypeFromUri(context->uri);
1396         string notifyUri = MediaLibraryNapiUtils::GetMediaTypeUri(mediaType);
1397         Uri modifyNotify(notifyUri);
1398         UserFileClient::NotifyChange(modifyNotify);
1399     } else {
1400         context->HandleError(env, jsContext->error);
1401     }
1402     if (context->work != nullptr) {
1403         tracer.Finish();
1404         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1405             context->work, *jsContext);
1406     }
1407 
1408     delete context;
1409 }
1410 
GetJSArgsForDeleteAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)1411 napi_value GetJSArgsForDeleteAsset(napi_env env, size_t argc, const napi_value argv[],
1412                                    MediaLibraryAsyncContext &asyncContext)
1413 {
1414     const int32_t refCount = 1;
1415     napi_value result = nullptr;
1416     auto context = &asyncContext;
1417     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1418     size_t res = 0;
1419     char buffer[PATH_MAX];
1420 
1421     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1422 
1423     for (size_t i = PARAM0; i < argc; i++) {
1424         napi_valuetype valueType = napi_undefined;
1425         napi_typeof(env, argv[i], &valueType);
1426 
1427         if (i == PARAM0 && valueType == napi_string) {
1428             napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
1429         } else if (i == PARAM1 && valueType == napi_function) {
1430             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1431             break;
1432         } else {
1433             NAPI_ASSERT(env, false, "type mismatch");
1434         }
1435     }
1436 
1437     context->valuesBucket.Put(MEDIA_DATA_DB_URI, string(buffer));
1438 
1439     // Return true napi_value if params are successfully obtained
1440     napi_get_boolean(env, true, &result);
1441     return result;
1442 }
1443 
JSDeleteAsset(napi_env env,napi_callback_info info)1444 napi_value MediaLibraryNapi::JSDeleteAsset(napi_env env, napi_callback_info info)
1445 {
1446     napi_status status;
1447     napi_value result = nullptr;
1448     size_t argc = ARGS_TWO;
1449     napi_value argv[ARGS_TWO] = {0};
1450     napi_value thisVar = nullptr;
1451 
1452     MediaLibraryTracer tracer;
1453     tracer.Start("JSDeleteAsset");
1454 
1455     GET_JS_ARGS(env, info, argc, argv, thisVar);
1456     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1457     napi_get_undefined(env, &result);
1458 
1459     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1460     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
1461     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1462         result = GetJSArgsForDeleteAsset(env, argc, argv, *asyncContext);
1463         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1464 
1465         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSDeleteAsset", JSDeleteAssetExecute,
1466             JSDeleteAssetCompleteCallback);
1467     }
1468 
1469     return result;
1470 }
1471 
OnChange(const MediaChangeListener & listener,const napi_ref cbRef)1472 void ChangeListenerNapi::OnChange(const MediaChangeListener &listener, const napi_ref cbRef)
1473 {
1474     uv_loop_s *loop = nullptr;
1475     napi_get_uv_event_loop(env_, &loop);
1476     if (loop == nullptr) {
1477         return;
1478     }
1479 
1480     uv_work_t *work = new (std::nothrow) uv_work_t;
1481     if (work == nullptr) {
1482         return;
1483     }
1484 
1485     UvChangeMsg *msg = new (std::nothrow) UvChangeMsg(env_, cbRef);
1486     if (msg == nullptr) {
1487         delete work;
1488         return;
1489     }
1490     work->data = reinterpret_cast<void *>(msg);
1491 
1492     int ret = uv_queue_work(loop, work, [](uv_work_t *w) {}, [](uv_work_t *w, int s) {
1493             // js thread
1494             if (w == nullptr) {
1495                 return;
1496             }
1497 
1498             UvChangeMsg *msg = reinterpret_cast<UvChangeMsg *>(w->data);
1499             do {
1500                 if (msg == nullptr) {
1501                     NAPI_ERR_LOG("UvChangeMsg is null");
1502                     break;
1503                 }
1504                 napi_env env = msg->env_;
1505                 napi_value result[ARGS_TWO] = { nullptr };
1506                 napi_get_undefined(env, &result[PARAM0]);
1507                 napi_get_undefined(env, &result[PARAM1]);
1508                 napi_value jsCallback = nullptr;
1509                 napi_status status = napi_get_reference_value(env, msg->ref_, &jsCallback);
1510                 if (status != napi_ok) {
1511                     NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
1512                     break;
1513                 }
1514                 napi_value retVal = nullptr;
1515                 napi_call_function(env, nullptr, jsCallback, ARGS_TWO, result, &retVal);
1516                 if (status != napi_ok) {
1517                     NAPI_ERR_LOG("CallJs napi_call_function fail, status: %{public}d", status);
1518                     break;
1519                 }
1520             } while (0);
1521             delete msg;
1522             delete w;
1523     });
1524     if (ret != 0) {
1525         NAPI_ERR_LOG("Failed to execute libuv work queue, ret: %{public}d", ret);
1526         delete msg;
1527         delete work;
1528     }
1529 }
1530 
GetListenerType(const std::string & str) const1531 int32_t MediaLibraryNapi::GetListenerType(const std::string &str) const
1532 {
1533     auto iter = ListenerTypeMaps.find(str);
1534     if (iter == ListenerTypeMaps.end()) {
1535         NAPI_ERR_LOG("Invalid Listener Type %{public}s", str.c_str());
1536         return INVALID_LISTENER;
1537     }
1538 
1539     return iter->second;
1540 }
1541 
RegisterChange(napi_env env,const std::string & type,ChangeListenerNapi & listObj)1542 void MediaLibraryNapi::RegisterChange(napi_env env, const std::string &type, ChangeListenerNapi &listObj)
1543 {
1544     NAPI_DEBUG_LOG("Register change type = %{public}s", type.c_str());
1545 
1546     int32_t typeEnum = GetListenerType(type);
1547     switch (typeEnum) {
1548         case AUDIO_LISTENER:
1549             listObj.audioDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_AUDIO);
1550             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
1551             break;
1552         case VIDEO_LISTENER:
1553             listObj.videoDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_VIDEO);
1554             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
1555             break;
1556         case IMAGE_LISTENER:
1557             listObj.imageDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_IMAGE);
1558             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
1559             break;
1560         case FILE_LISTENER:
1561             listObj.fileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_FILE);
1562             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
1563             break;
1564         case SMARTALBUM_LISTENER:
1565             listObj.smartAlbumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_SMARTALBUM);
1566             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
1567                 listObj.smartAlbumDataObserver_);
1568             break;
1569         case DEVICE_LISTENER:
1570             listObj.deviceDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_DEVICE);
1571             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
1572             break;
1573         case REMOTEFILE_LISTENER:
1574             listObj.remoteFileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_REMOTEFILE);
1575             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
1576             break;
1577         case ALBUM_LISTENER:
1578             listObj.albumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_ALBUM);
1579             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
1580             break;
1581         default:
1582             NAPI_ERR_LOG("Invalid Media Type!");
1583     }
1584 }
1585 
JSOnCallback(napi_env env,napi_callback_info info)1586 napi_value MediaLibraryNapi::JSOnCallback(napi_env env, napi_callback_info info)
1587 {
1588     napi_value undefinedResult = nullptr;
1589     size_t argc = ARGS_TWO;
1590     napi_value argv[ARGS_TWO] = {nullptr};
1591     napi_value thisVar = nullptr;
1592     size_t res = 0;
1593     char buffer[ARG_BUF_SIZE];
1594     string type;
1595     const int32_t refCount = 1;
1596     MediaLibraryNapi *obj = nullptr;
1597     napi_status status;
1598 
1599     MediaLibraryTracer tracer;
1600     tracer.Start("JSOnCallback");
1601 
1602     napi_get_undefined(env, &undefinedResult);
1603     GET_JS_ARGS(env, info, argc, argv, thisVar);
1604     NAPI_ASSERT(env, argc == ARGS_TWO, "requires 2 parameters");
1605     if (thisVar == nullptr || argv[PARAM0] == nullptr || argv[PARAM1] == nullptr) {
1606         NAPI_ERR_LOG("Failed to retrieve details about the callback");
1607         return undefinedResult;
1608     }
1609 
1610     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
1611     if (status == napi_ok && obj != nullptr) {
1612         napi_valuetype valueType = napi_undefined;
1613         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
1614             napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
1615             return undefinedResult;
1616         }
1617 
1618         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
1619             NAPI_ERR_LOG("Failed to get value string utf8 for type");
1620             return undefinedResult;
1621         }
1622         type = string(buffer);
1623 
1624         napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOnRef_);
1625 
1626         tracer.Start("RegisterChange");
1627         obj->RegisterChange(env, type, *g_listObj);
1628         tracer.Finish();
1629     }
1630 
1631     return undefinedResult;
1632 }
1633 
UnregisterChange(napi_env env,const string & type,ChangeListenerNapi & listObj)1634 void MediaLibraryNapi::UnregisterChange(napi_env env, const string &type, ChangeListenerNapi &listObj)
1635 {
1636     NAPI_DEBUG_LOG("Unregister change type = %{public}s", type.c_str());
1637 
1638     MediaType mediaType;
1639     int32_t typeEnum = GetListenerType(type);
1640 
1641     switch (typeEnum) {
1642         case AUDIO_LISTENER:
1643             CHECK_NULL_PTR_RETURN_VOID(listObj.audioDataObserver_, "Failed to obtain audio data observer");
1644             mediaType = MEDIA_TYPE_AUDIO;
1645             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
1646             listObj.audioDataObserver_ = nullptr;
1647             break;
1648         case VIDEO_LISTENER:
1649             CHECK_NULL_PTR_RETURN_VOID(listObj.videoDataObserver_, "Failed to obtain video data observer");
1650             mediaType = MEDIA_TYPE_VIDEO;
1651             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
1652             listObj.videoDataObserver_ = nullptr;
1653             break;
1654         case IMAGE_LISTENER:
1655             CHECK_NULL_PTR_RETURN_VOID(listObj.imageDataObserver_, "Failed to obtain image data observer");
1656             mediaType = MEDIA_TYPE_IMAGE;
1657             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
1658             listObj.imageDataObserver_ = nullptr;
1659             break;
1660         case FILE_LISTENER:
1661             CHECK_NULL_PTR_RETURN_VOID(listObj.fileDataObserver_, "Failed to obtain file data observer");
1662             mediaType = MEDIA_TYPE_FILE;
1663             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
1664             listObj.fileDataObserver_ = nullptr;
1665             break;
1666         case SMARTALBUM_LISTENER:
1667             CHECK_NULL_PTR_RETURN_VOID(listObj.smartAlbumDataObserver_, "Failed to obtain smart album data observer");
1668             mediaType = MEDIA_TYPE_SMARTALBUM;
1669             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
1670                 listObj.smartAlbumDataObserver_);
1671             listObj.smartAlbumDataObserver_ = nullptr;
1672             break;
1673         case DEVICE_LISTENER:
1674             CHECK_NULL_PTR_RETURN_VOID(listObj.deviceDataObserver_, "Failed to obtain device data observer");
1675             mediaType = MEDIA_TYPE_DEVICE;
1676             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
1677             listObj.deviceDataObserver_ = nullptr;
1678             break;
1679         case REMOTEFILE_LISTENER:
1680             CHECK_NULL_PTR_RETURN_VOID(listObj.remoteFileDataObserver_, "Failed to obtain remote file data observer");
1681             mediaType = MEDIA_TYPE_REMOTEFILE;
1682             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
1683             listObj.remoteFileDataObserver_ = nullptr;
1684             break;
1685         case ALBUM_LISTENER:
1686             CHECK_NULL_PTR_RETURN_VOID(listObj.albumDataObserver_, "Failed to obtain album data observer");
1687             mediaType = MEDIA_TYPE_ALBUM;
1688             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
1689             listObj.albumDataObserver_ = nullptr;
1690             break;
1691         default:
1692             NAPI_ERR_LOG("Invalid Media Type");
1693             return;
1694     }
1695 
1696     if (listObj.cbOffRef_ != nullptr) {
1697         MediaChangeListener listener;
1698         listener.mediaType = mediaType;
1699         listObj.OnChange(listener, listObj.cbOffRef_);
1700     }
1701 }
1702 
JSOffCallback(napi_env env,napi_callback_info info)1703 napi_value MediaLibraryNapi::JSOffCallback(napi_env env, napi_callback_info info)
1704 {
1705     napi_value undefinedResult = nullptr;
1706     size_t argc = ARGS_TWO;
1707     napi_value argv[ARGS_TWO] = {nullptr};
1708     napi_value thisVar = nullptr;
1709     size_t res = 0;
1710     char buffer[ARG_BUF_SIZE];
1711     const int32_t refCount = 1;
1712     string type;
1713     MediaLibraryNapi *obj = nullptr;
1714     napi_status status;
1715 
1716     MediaLibraryTracer tracer;
1717     tracer.Start("JSOffCallback");
1718 
1719     napi_get_undefined(env, &undefinedResult);
1720     GET_JS_ARGS(env, info, argc, argv, thisVar);
1721     NAPI_ASSERT(env, ARGS_ONE <= argc && argc<= ARGS_TWO, "requires one or two parameters");
1722     if (thisVar == nullptr || argv[PARAM0] == nullptr) {
1723         NAPI_ERR_LOG("Failed to retrieve details about the callback");
1724         return undefinedResult;
1725     }
1726 
1727     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
1728     if (status == napi_ok && obj != nullptr) {
1729         napi_valuetype valueType = napi_undefined;
1730         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
1731             return undefinedResult;
1732         }
1733 
1734         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
1735             NAPI_ERR_LOG("Failed to get value string utf8 for type");
1736             return undefinedResult;
1737         }
1738         type = string(buffer);
1739 
1740         if (argc == ARGS_TWO) {
1741             if (napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function ||
1742                 g_listObj == nullptr) {
1743                 return undefinedResult;
1744             }
1745 
1746             napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOffRef_);
1747         }
1748 
1749         tracer.Start("UnregisterChange");
1750         obj->UnregisterChange(env, type, *g_listObj);
1751         tracer.Finish();
1752     }
1753 
1754     return undefinedResult;
1755 }
1756 
JSReleaseCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)1757 static void JSReleaseCompleteCallback(napi_env env, napi_status status,
1758                                       MediaLibraryAsyncContext *context)
1759 {
1760     MediaLibraryTracer tracer;
1761     tracer.Start("JSReleaseCompleteCallback");
1762 
1763     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1764 
1765     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1766     jsContext->status = false;
1767     if (context->objectInfo != nullptr) {
1768         context->objectInfo->~MediaLibraryNapi();
1769         napi_create_int32(env, SUCCESS, &jsContext->data);
1770         jsContext->status = true;
1771         napi_get_undefined(env, &jsContext->error);
1772     } else {
1773         NAPI_ERR_LOG("JSReleaseCompleteCallback context->objectInfo == nullptr");
1774         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1775             "UserFileClient is invalid");
1776         napi_get_undefined(env, &jsContext->data);
1777     }
1778 
1779     tracer.Finish();
1780     if (context->work != nullptr) {
1781         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1782                                                    context->work, *jsContext);
1783     }
1784 
1785     delete context;
1786 }
1787 
JSRelease(napi_env env,napi_callback_info info)1788 napi_value MediaLibraryNapi::JSRelease(napi_env env, napi_callback_info info)
1789 {
1790     napi_status status;
1791     napi_value result = nullptr;
1792     size_t argc = ARGS_ONE;
1793     napi_value argv[ARGS_ONE] = {0};
1794     napi_value thisVar = nullptr;
1795     napi_value resource = nullptr;
1796     int32_t refCount = 1;
1797 
1798     MediaLibraryTracer tracer;
1799     tracer.Start("JSRelease");
1800 
1801     GET_JS_ARGS(env, info, argc, argv, thisVar);
1802     NAPI_ERR_LOG("NAPI_ASSERT begin %{public}zu", argc);
1803     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_ZERO), "requires 1 parameters maximum");
1804     NAPI_ERR_LOG("NAPI_ASSERT end");
1805     napi_get_undefined(env, &result);
1806 
1807     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1808     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
1809     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1810         if (argc == PARAM1) {
1811             napi_valuetype valueType = napi_undefined;
1812             napi_typeof(env, argv[PARAM0], &valueType);
1813             if (valueType == napi_function) {
1814                 napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
1815             }
1816         }
1817         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1818 
1819         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
1820         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSRelease", asyncContext);
1821 
1822         status = napi_create_async_work(
1823             env, nullptr, resource, [](napi_env env, void* data) {},
1824             reinterpret_cast<CompleteCallback>(JSReleaseCompleteCallback),
1825             static_cast<void*>(asyncContext.get()), &asyncContext->work);
1826         if (status != napi_ok) {
1827             napi_get_undefined(env, &result);
1828         } else {
1829             napi_queue_async_work(env, asyncContext->work);
1830             asyncContext.release();
1831         }
1832     }
1833 
1834     return result;
1835 }
1836 
SetSmartAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<SmartAlbumAsset> & smartAlbum)1837 static void SetSmartAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<SmartAlbumAsset> &smartAlbum)
1838 {
1839     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1840     if (smartAlbum->GetAlbumCapacity() == 0) {
1841         return;
1842     }
1843     DataShare::DataSharePredicates predicates;
1844     string trashPrefix;
1845     if (smartAlbum->GetAlbumId() == TRASH_ALBUM_ID_VALUES) {
1846         trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " <> ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
1847     } else {
1848         trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
1849     }
1850     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
1851     context->selectionArgs.emplace_back("0");
1852     context->selectionArgs.emplace_back(std::to_string(smartAlbum->GetAlbumId()));
1853     predicates.SetOrder(SMARTALBUMMAP_DB_ID + " DESC");
1854     predicates.SetWhereClause(context->selection);
1855     predicates.SetWhereArgs(context->selectionArgs);
1856     std::vector<std::string> columns;
1857     Uri uri(MEDIALIBRARY_DATA_URI + "/"
1858                + MEDIA_ALBUMOPRN_QUERYALBUM + "/"
1859                + ASSETMAP_VIEW_NAME);
1860 
1861     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns);
1862     unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1863     unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
1864     CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetSmartAlbumCoverUri fileAsset is nullptr");
1865     string coverUri = fileAsset->GetUri();
1866     smartAlbum->SetCoverUri(coverUri);
1867     NAPI_DEBUG_LOG("coverUri is = %{private}s", smartAlbum->GetCoverUri().c_str());
1868 }
1869 
SetSmartAlbumData(SmartAlbumAsset * smartAlbumData,shared_ptr<DataShare::DataShareResultSet> resultSet,MediaLibraryAsyncContext * context)1870 static void SetSmartAlbumData(SmartAlbumAsset* smartAlbumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
1871     MediaLibraryAsyncContext *context)
1872 {
1873     CHECK_NULL_PTR_RETURN_VOID(smartAlbumData, "albumData is null");
1874     smartAlbumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_ID, resultSet, TYPE_INT32)));
1875     smartAlbumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_NAME, resultSet,
1876         TYPE_STRING)));
1877     smartAlbumData->SetAlbumCapacity(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_CAPACITY,
1878         resultSet, TYPE_INT32)));
1879     smartAlbumData->SetAlbumUri(GetFileMediaTypeUri(MEDIA_TYPE_SMARTALBUM, context->networkId) +
1880         "/" + to_string(smartAlbumData->GetAlbumId()));
1881     smartAlbumData->SetTypeMask(context->typeMask);
1882 }
1883 
GetAllSmartAlbumResultDataExecute(napi_env env,void * data)1884 static void GetAllSmartAlbumResultDataExecute(napi_env env, void *data)
1885 {
1886     MediaLibraryTracer tracer;
1887     tracer.Start("GetResultDataExecute");
1888 
1889     auto context = static_cast<MediaLibraryAsyncContext *>(data);
1890     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1891     NAPI_INFO_LOG("context->privateAlbumType = %{public}d", context->privateAlbumType);
1892 
1893     if (context->privateAlbumType == TYPE_TRASH) {
1894         context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(TRASH_ALBUM_ID_VALUES));
1895         NAPI_INFO_LOG("context->privateAlbumType == TYPE_TRASH");
1896     }
1897     if (context->privateAlbumType == TYPE_FAVORITE) {
1898         context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(FAVOURITE_ALBUM_ID_VALUES));
1899         NAPI_INFO_LOG("context->privateAlbumType == TYPE_FAVORITE");
1900     }
1901 
1902     vector<string> columns;
1903     string uriStr = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
1904     if (!context->networkId.empty()) {
1905         uriStr = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER +
1906             "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
1907     }
1908     MediaLibraryNapiUtils::UriAddFragmentTypeMask(uriStr, context->typeMask);
1909     Uri uri(uriStr);
1910     auto resultSet = UserFileClient::Query(uri, context->predicates, columns);
1911     if (resultSet == nullptr) {
1912         NAPI_ERR_LOG("resultSet == nullptr");
1913         return;
1914     }
1915 
1916     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
1917         context->fetchSmartAlbumResult = make_unique<FetchResult<SmartAlbumAsset>>(move(resultSet));
1918         context->fetchSmartAlbumResult->SetNetworkId(context->networkId);
1919         context->fetchSmartAlbumResult->resultNapiType_ = context->resultNapiType;
1920         context->fetchSmartAlbumResult->typeMask_ = context->typeMask;
1921         return;
1922     }
1923     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1924         unique_ptr<SmartAlbumAsset> albumData = make_unique<SmartAlbumAsset>();
1925         SetSmartAlbumData(albumData.get(), resultSet, context);
1926         SetSmartAlbumCoverUri(context, albumData);
1927 
1928         context->privateSmartAlbumNativeArray.push_back(move(albumData));
1929     }
1930 }
1931 
MediaLibSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1932 static void MediaLibSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1933     unique_ptr<JSAsyncContextOutput> &jsContext)
1934 {
1935     if (context->smartAlbumData != nullptr) {
1936         NAPI_ERR_LOG("context->smartAlbumData != nullptr");
1937         jsContext->status = true;
1938         napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumData);
1939         napi_get_undefined(env, &jsContext->error);
1940         jsContext->data = albumNapiObj;
1941     } else if (!context->privateSmartAlbumNativeArray.empty()) {
1942         NAPI_ERR_LOG("context->privateSmartAlbumNativeArray.empty()");
1943         jsContext->status = true;
1944         napi_value albumArray = nullptr;
1945         napi_create_array(env, &albumArray);
1946         for (size_t i = 0; i < context->privateSmartAlbumNativeArray.size(); i++) {
1947             napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
1948                 context->privateSmartAlbumNativeArray[i]);
1949             napi_set_element(env, albumArray, i, albumNapiObj);
1950         }
1951         napi_get_undefined(env, &jsContext->error);
1952         jsContext->data = albumArray;
1953     } else {
1954         NAPI_ERR_LOG("No fetch file result found!");
1955         napi_get_undefined(env, &jsContext->data);
1956         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1957             "Failed to obtain Fetch File Result");
1958     }
1959 }
1960 
UserFileMgrSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1961 static void UserFileMgrSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1962     unique_ptr<JSAsyncContextOutput> &jsContext)
1963 {
1964     if (context->fetchSmartAlbumResult->GetCount() < 0) {
1965         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1966             "find no data by options");
1967     } else {
1968         napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchSmartAlbumResult));
1969         if (fileResult == nullptr) {
1970             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1971                 "Failed to create js object for Fetch SmartAlbum Result");
1972         } else {
1973             jsContext->data = fileResult;
1974             jsContext->status = true;
1975             napi_get_undefined(env, &jsContext->error);
1976         }
1977     }
1978 }
1979 
SmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1980 static void SmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1981     unique_ptr<JSAsyncContextOutput> &jsContext)
1982 {
1983     if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
1984         MediaLibSmartAlbumsAsyncResult(env, context, jsContext);
1985     } else {
1986         UserFileMgrSmartAlbumsAsyncResult(env, context, jsContext);
1987     }
1988 }
1989 
GetPrivateAlbumCallbackComplete(napi_env env,napi_status status,void * data)1990 static void GetPrivateAlbumCallbackComplete(napi_env env, napi_status status, void *data)
1991 {
1992     MediaLibraryTracer tracer;
1993     tracer.Start("GetPrivateAlbumCallbackComplete");
1994 
1995     auto context = static_cast<MediaLibraryAsyncContext *>(data);
1996     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1997     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1998     jsContext->status = false;
1999     napi_get_undefined(env, &jsContext->error);
2000     if (context->error != ERR_DEFAULT) {
2001         napi_get_undefined(env, &jsContext->data);
2002         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2003             "Query for get fileAssets failed");
2004     } else {
2005         SmartAlbumsAsyncResult(env, context, jsContext);
2006     }
2007 
2008     tracer.Finish();
2009     if (context->work != nullptr) {
2010         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2011                                                    context->work, *jsContext);
2012     }
2013     delete context;
2014 }
2015 
SmartAlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)2016 static void SmartAlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
2017 {
2018     auto context = static_cast<MediaLibraryAsyncContext *>(data);
2019     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2020     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2021     jsContext->status = false;
2022     napi_get_undefined(env, &jsContext->error);
2023     if (context->error != ERR_DEFAULT) {
2024         napi_get_undefined(env, &jsContext->data);
2025         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2026             "Query for get smartAlbums failed");
2027     } else {
2028         if (!context->smartAlbumNativeArray.empty()) {
2029             jsContext->status = true;
2030             napi_value albumArray = nullptr;
2031             napi_create_array(env, &albumArray);
2032             for (size_t i = 0; i < context->smartAlbumNativeArray.size(); i++) {
2033                 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
2034                     context->smartAlbumNativeArray[i]);
2035                 napi_set_element(env, albumArray, i, albumNapiObj);
2036             }
2037             napi_get_undefined(env, &jsContext->error);
2038             jsContext->data = albumArray;
2039         } else {
2040             NAPI_ERR_LOG("No SmartAlbums result found!");
2041             napi_get_undefined(env, &jsContext->data);
2042             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2043                 "Failed to obtain SmartAlbums Result");
2044         }
2045     }
2046     if (context->work != nullptr) {
2047         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2048                                                    context->work, *jsContext);
2049     }
2050     delete context;
2051 }
2052 
JSGetSmartAlbums(napi_env env,napi_callback_info info)2053 napi_value MediaLibraryNapi::JSGetSmartAlbums(napi_env env, napi_callback_info info)
2054 {
2055     napi_status status;
2056     napi_value result = nullptr;
2057     size_t argc = ARGS_TWO;
2058     napi_value argv[ARGS_TWO] = {0};
2059     napi_value thisVar = nullptr;
2060 
2061     GET_JS_ARGS(env, info, argc, argv, thisVar);
2062     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2063     napi_get_undefined(env, &result);
2064     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2065     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Async context is null");
2066     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2067     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2068         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
2069         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
2070 
2071         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetSmartAlbums",
2072             GetAllSmartAlbumResultDataExecute, SmartAlbumsAsyncCallbackComplete);
2073     }
2074 
2075     return result;
2076 }
2077 
JSGetPrivateAlbum(napi_env env,napi_callback_info info)2078 napi_value MediaLibraryNapi::JSGetPrivateAlbum(napi_env env, napi_callback_info info)
2079 {
2080     napi_status status;
2081     napi_value result = nullptr;
2082     size_t argc = ARGS_TWO;
2083     napi_value argv[ARGS_TWO] = {0};
2084     napi_value thisVar = nullptr;
2085     const int32_t refCount = 1;
2086 
2087     GET_JS_ARGS(env, info, argc, argv, thisVar);
2088     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2089     napi_get_undefined(env, &result);
2090     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2091     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2092     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2093         for (size_t i = PARAM0; i < argc; i++) {
2094             napi_valuetype valueType = napi_undefined;
2095             napi_typeof(env, argv[i], &valueType);
2096             if (i == PARAM0 && valueType == napi_number) {
2097                 napi_get_value_int32(env, argv[i], &asyncContext->privateAlbumType);
2098             } else if (i == PARAM1 && valueType == napi_function) {
2099                 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
2100                 break;
2101             } else {
2102                 NAPI_ASSERT(env, false, "type mismatch");
2103             }
2104         }
2105         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPrivateAlbum",
2106             GetAllSmartAlbumResultDataExecute, GetPrivateAlbumCallbackComplete);
2107     }
2108     return result;
2109 }
2110 
GetJSArgsForCreateSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)2111 napi_value GetJSArgsForCreateSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
2112                                         MediaLibraryAsyncContext &asyncContext)
2113 {
2114     const int32_t refCount = 1;
2115     napi_value result = nullptr;
2116     auto context = &asyncContext;
2117     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2118     size_t res = 0;
2119     char buffer[PATH_MAX];
2120     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2121     for (size_t i = PARAM0; i < argc; i++) {
2122         napi_valuetype valueType = napi_undefined;
2123         napi_typeof(env, argv[i], &valueType);
2124         if (i == PARAM0 && valueType == napi_string) {
2125             napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
2126         } else if (i == PARAM1 && valueType == napi_function) {
2127             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2128             break;
2129         } else {
2130             NAPI_ASSERT(env, false, "type mismatch");
2131         }
2132     }
2133     context->valuesBucket.Put(SMARTALBUM_DB_NAME, string(buffer));
2134     napi_get_boolean(env, true, &result);
2135     return result;
2136 }
2137 
JSCreateSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2138 static void JSCreateSmartAlbumCompleteCallback(napi_env env, napi_status status,
2139                                                MediaLibraryAsyncContext *context)
2140 {
2141     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2142     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2143     jsContext->status = false;
2144     if (context->error == ERR_DEFAULT) {
2145         if (context->smartAlbumNativeArray.empty()) {
2146             NAPI_ERR_LOG("No albums found");
2147             napi_get_undefined(env, &jsContext->data);
2148             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2149                 "No albums found");
2150         } else {
2151             jsContext->status = true;
2152             napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumNativeArray[0]);
2153             jsContext->data = albumNapiObj;
2154             napi_get_undefined(env, &jsContext->error);
2155         }
2156     } else {
2157         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2158             "File asset creation failed");
2159         napi_get_undefined(env, &jsContext->data);
2160     }
2161     if (context->work != nullptr) {
2162         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2163                                                    context->work, *jsContext);
2164     }
2165     delete context;
2166 }
2167 
JSCreateSmartAlbum(napi_env env,napi_callback_info info)2168 napi_value MediaLibraryNapi::JSCreateSmartAlbum(napi_env env, napi_callback_info info)
2169 {
2170     napi_status status;
2171     napi_value result = nullptr;
2172     size_t argc = ARGS_TWO;
2173     napi_value argv[ARGS_TWO] = {0};
2174     napi_value thisVar = nullptr;
2175     napi_value resource = nullptr;
2176 
2177     GET_JS_ARGS(env, info, argc, argv, thisVar);
2178     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2179     napi_get_undefined(env, &result);
2180     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2181     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2182     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2183         result = GetJSArgsForCreateSmartAlbum(env, argc, argv, *asyncContext);
2184         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
2185         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2186         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSCreateSmartAlbum", asyncContext);
2187         status = napi_create_async_work(
2188             env, nullptr, resource, [](napi_env env, void *data) {
2189                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
2190                 string abilityUri = MEDIALIBRARY_DATA_URI;
2191                 Uri CreateSmartAlbumUri(abilityUri + "/" + MEDIA_SMARTALBUMOPRN + "/" +
2192                     MEDIA_SMARTALBUMOPRN_CREATEALBUM);
2193                 int retVal = UserFileClient::Insert(CreateSmartAlbumUri, context->valuesBucket);
2194                 if (retVal > 0) {
2195                     context->selection = SMARTALBUM_DB_ID + " = ?";
2196                     context->selectionArgs = {std::to_string(retVal)};
2197                     context->retVal = retVal;
2198                 } else {
2199                     context->error = retVal;
2200                 }
2201             },
2202             reinterpret_cast<CompleteCallback>(JSCreateSmartAlbumCompleteCallback),
2203             static_cast<void*>(asyncContext.get()), &asyncContext->work);
2204         if (status != napi_ok) {
2205             napi_get_undefined(env, &result);
2206         } else {
2207             napi_queue_async_work(env, asyncContext->work);
2208             asyncContext.release();
2209         }
2210     }
2211     return result;
2212 }
2213 
GetJSArgsForDeleteSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)2214 napi_value GetJSArgsForDeleteSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
2215                                         MediaLibraryAsyncContext &asyncContext)
2216 {
2217     const int32_t refCount = 1;
2218     napi_value result = nullptr;
2219     auto context = &asyncContext;
2220     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2221     size_t res = 0;
2222     char buffer[PATH_MAX];
2223     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2224     for (size_t i = PARAM0; i < argc; i++) {
2225         napi_valuetype valueType = napi_undefined;
2226         napi_typeof(env, argv[i], &valueType);
2227         if (i == PARAM0 && valueType == napi_string) {
2228             napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
2229         } else if (i == PARAM1 && valueType == napi_function) {
2230             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2231             break;
2232         } else {
2233             NAPI_ASSERT(env, false, "type mismatch");
2234         }
2235     }
2236     std::string coverUri = string(buffer);
2237     std::string strRow;
2238     string::size_type pos = coverUri.find_last_of('/');
2239     strRow = coverUri.substr(pos + 1);
2240     context->valuesBucket.Put(SMARTALBUM_DB_ID, std::stoi(strRow));
2241     napi_get_boolean(env, true, &result);
2242     return result;
2243 }
2244 
JSDeleteSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2245 static void JSDeleteSmartAlbumCompleteCallback(napi_env env, napi_status status,
2246                                                MediaLibraryAsyncContext *context)
2247 {
2248     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2249     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2250     jsContext->status = false;
2251     if (context->error == ERR_DEFAULT) {
2252         napi_create_int32(env, context->retVal, &jsContext->data);
2253         napi_get_undefined(env, &jsContext->error);
2254         jsContext->status = true;
2255     } else {
2256         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2257             "UserFileClient is invalid");
2258         napi_get_undefined(env, &jsContext->data);
2259     }
2260     if (context->work != nullptr) {
2261         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2262                                                    context->work, *jsContext);
2263     }
2264     delete context;
2265 }
2266 
JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext * context)2267 static void JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext *context)
2268 {
2269     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2270     bool isValid = false;
2271     int32_t smartAlbumId = context->valuesBucket.Get(SMARTALBUM_DB_ID, isValid);
2272     if (!isValid) {
2273         context->error = ERR_INVALID_OUTPUT;
2274         return;
2275     }
2276     string abilityUri = MEDIALIBRARY_DATA_URI;
2277     Uri DeleteSmartAlbumUri(abilityUri + "/" + MEDIA_SMARTALBUMOPRN + "/" +
2278         MEDIA_SMARTALBUMOPRN_DELETEALBUM + '/' + to_string(smartAlbumId));
2279     DataSharePredicates predicates;
2280     int retVal = UserFileClient::Delete(DeleteSmartAlbumUri, predicates);
2281     NAPI_DEBUG_LOG("JSDeleteSmartAlbumCompleteCallback retVal = %{public}d", retVal);
2282     if (retVal < 0) {
2283         context->error = retVal;
2284     } else {
2285         context->retVal = retVal;
2286     }
2287 }
2288 
JSDeleteSmartAlbum(napi_env env,napi_callback_info info)2289 napi_value MediaLibraryNapi::JSDeleteSmartAlbum(napi_env env, napi_callback_info info)
2290 {
2291     napi_status status;
2292     napi_value result = nullptr;
2293     size_t argc = ARGS_TWO;
2294     napi_value argv[ARGS_TWO] = {0};
2295     napi_value thisVar = nullptr;
2296     napi_value resource = nullptr;
2297 
2298     GET_JS_ARGS(env, info, argc, argv, thisVar);
2299     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2300     napi_get_undefined(env, &result);
2301     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2302     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2303     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2304         result = GetJSArgsForDeleteSmartAlbum(env, argc, argv, *asyncContext);
2305         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
2306         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2307         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSDeleteSmartAlbum", asyncContext);
2308         status = napi_create_async_work(
2309             env, nullptr, resource, [](napi_env env, void* data) {
2310                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
2311                 JSDeleteSmartAlbumExecute(context);
2312             },
2313             reinterpret_cast<CompleteCallback>(JSDeleteSmartAlbumCompleteCallback),
2314             static_cast<void*>(asyncContext.get()), &asyncContext->work);
2315         if (status != napi_ok) {
2316             napi_get_undefined(env, &result);
2317         } else {
2318             napi_queue_async_work(env, asyncContext->work);
2319             asyncContext.release();
2320         }
2321     }
2322     return result;
2323 }
2324 
SetValueUtf8String(const napi_env & env,const char * fieldStr,const char * str,napi_value & result)2325 static napi_status SetValueUtf8String(const napi_env& env, const char* fieldStr, const char* str, napi_value& result)
2326 {
2327     napi_value value;
2328     napi_status status = napi_create_string_utf8(env, str, NAPI_AUTO_LENGTH, &value);
2329     if (status != napi_ok) {
2330         NAPI_ERR_LOG("Set value create utf8 string error! field: %{public}s", fieldStr);
2331         return status;
2332     }
2333     status = napi_set_named_property(env, result, fieldStr, value);
2334     if (status != napi_ok) {
2335         NAPI_ERR_LOG("Set utf8 string named property error! field: %{public}s", fieldStr);
2336     }
2337     return status;
2338 }
2339 
SetValueInt32(const napi_env & env,const char * fieldStr,const int intValue,napi_value & result)2340 static napi_status SetValueInt32(const napi_env& env, const char* fieldStr, const int intValue, napi_value& result)
2341 {
2342     napi_value value;
2343     napi_status status = napi_create_int32(env, intValue, &value);
2344     if (status != napi_ok) {
2345         NAPI_ERR_LOG("Set value create int32 error! field: %{public}s", fieldStr);
2346         return status;
2347     }
2348     status = napi_set_named_property(env, result, fieldStr, value);
2349     if (status != napi_ok) {
2350         NAPI_ERR_LOG("Set int32 named property error! field: %{public}s", fieldStr);
2351     }
2352     return status;
2353 }
2354 
SetValueBool(const napi_env & env,const char * fieldStr,const bool boolvalue,napi_value & result)2355 static napi_status SetValueBool(const napi_env& env, const char* fieldStr, const bool boolvalue, napi_value& result)
2356 {
2357     napi_value value = nullptr;
2358     napi_status status = napi_get_boolean(env, boolvalue, &value);
2359     if (status != napi_ok) {
2360         NAPI_ERR_LOG("Set value create boolean error! field: %{public}s", fieldStr);
2361         return status;
2362     }
2363     status = napi_set_named_property(env, result, fieldStr, value);
2364     if (status != napi_ok) {
2365         NAPI_ERR_LOG("Set boolean named property error! field: %{public}s", fieldStr);
2366     }
2367     return status;
2368 }
2369 
PeerInfoToJsArray(const napi_env & env,const std::vector<unique_ptr<PeerInfo>> & vecPeerInfo,const int32_t idx,napi_value & arrayResult)2370 static void PeerInfoToJsArray(const napi_env &env, const std::vector<unique_ptr<PeerInfo>> &vecPeerInfo,
2371     const int32_t idx, napi_value &arrayResult)
2372 {
2373     if (idx >= (int32_t) vecPeerInfo.size()) {
2374         return;
2375     }
2376     auto info = vecPeerInfo[idx].get();
2377     if (info == nullptr) {
2378         return;
2379     }
2380     napi_value result = nullptr;
2381     napi_create_object(env, &result);
2382     SetValueUtf8String(env, "deviceName", info->deviceName.c_str(), result);
2383     SetValueUtf8String(env, "networkId", info->networkId.c_str(), result);
2384     SetValueInt32(env, "deviceTypeId", (int) info->deviceTypeId, result);
2385     SetValueBool(env, "isOnline", info->isOnline, result);
2386 
2387     napi_status status = napi_set_element(env, arrayResult, idx, result);
2388     if (status != napi_ok) {
2389         NAPI_ERR_LOG("PeerInfo To JsArray set element error: %d", status);
2390     }
2391 }
2392 
JSGetActivePeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2393 void JSGetActivePeersCompleteCallback(napi_env env, napi_status status,
2394     MediaLibraryAsyncContext *context)
2395 {
2396     napi_value jsPeerInfoArray = nullptr;
2397 
2398     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2399 
2400     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2401     jsContext->status = false;
2402     napi_get_undefined(env, &jsContext->data);
2403 
2404     vector<std::string> columns;
2405     DataShare::DataSharePredicates predicates;
2406     std::string strQueryCondition = DEVICE_DB_DATE_MODIFIED + " = 0";
2407     predicates.SetWhereClause(strQueryCondition);
2408     predicates.SetWhereArgs(context->selectionArgs);
2409 
2410     Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYACTIVEDEVICE);
2411     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
2412         uri, predicates, columns);
2413 
2414     if (resultSet == nullptr) {
2415         NAPI_ERR_LOG("JSGetActivePeers resultSet is null");
2416         delete context;
2417         return;
2418     }
2419 
2420     vector<unique_ptr<PeerInfo>> peerInfoArray;
2421     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
2422         unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
2423         if (peerInfo != nullptr) {
2424             peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
2425                 TYPE_STRING));
2426             peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
2427                 TYPE_STRING));
2428             peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
2429                 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
2430             peerInfo->isOnline = true;
2431             peerInfoArray.push_back(move(peerInfo));
2432         }
2433     }
2434 
2435     if (!peerInfoArray.empty() && (napi_create_array(env, &jsPeerInfoArray) == napi_ok)) {
2436         for (size_t i = 0; i < peerInfoArray.size(); ++i) {
2437             PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
2438         }
2439 
2440         jsContext->data = jsPeerInfoArray;
2441         napi_get_undefined(env, &jsContext->error);
2442         jsContext->status = true;
2443     } else {
2444         NAPI_DEBUG_LOG("No peer info found!");
2445         napi_get_undefined(env, &jsContext->data);
2446         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2447             "Failed to obtain peer info array from DB");
2448     }
2449 
2450     if (context->work != nullptr) {
2451         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2452                                                    context->work, *jsContext);
2453     }
2454 
2455     delete context;
2456 }
2457 
JSGetAllPeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2458 void JSGetAllPeersCompleteCallback(napi_env env, napi_status status,
2459     MediaLibraryAsyncContext *context)
2460 {
2461     napi_value jsPeerInfoArray = nullptr;
2462 
2463     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2464 
2465     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2466     jsContext->status = false;
2467     napi_get_undefined(env, &jsContext->data);
2468 
2469     vector<string> columns;
2470     DataShare::DataSharePredicates predicates;
2471     predicates.SetWhereClause(context->selection);
2472     predicates.SetWhereArgs(context->selectionArgs);
2473 
2474     Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYALLDEVICE);
2475     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
2476         uri, predicates, columns);
2477 
2478     if (resultSet == nullptr) {
2479         NAPI_ERR_LOG("JSGetAllPeers resultSet is null");
2480         delete context;
2481         return;
2482     }
2483 
2484     vector<unique_ptr<PeerInfo>> peerInfoArray;
2485     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
2486         unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
2487         if (peerInfo != nullptr) {
2488             peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
2489                 TYPE_STRING));
2490             peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
2491                 TYPE_STRING));
2492             peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
2493                 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
2494             peerInfo->isOnline = (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_DATE_MODIFIED, resultSet,
2495                 TYPE_INT32)) == 0);
2496             peerInfoArray.push_back(move(peerInfo));
2497         }
2498     }
2499 
2500     if (!peerInfoArray.empty() && (napi_create_array(env, &jsPeerInfoArray) == napi_ok)) {
2501         for (size_t i = 0; i < peerInfoArray.size(); ++i) {
2502             PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
2503         }
2504 
2505         jsContext->data = jsPeerInfoArray;
2506         napi_get_undefined(env, &jsContext->error);
2507         jsContext->status = true;
2508     } else {
2509         NAPI_DEBUG_LOG("No peer info found!");
2510         napi_get_undefined(env, &jsContext->data);
2511         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2512             "Failed to obtain peer info array from DB");
2513     }
2514 
2515     if (context->work != nullptr) {
2516         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2517                                                    context->work, *jsContext);
2518     }
2519     delete context;
2520 }
2521 
JSGetActivePeers(napi_env env,napi_callback_info info)2522 napi_value MediaLibraryNapi::JSGetActivePeers(napi_env env, napi_callback_info info)
2523 {
2524     napi_status status;
2525     napi_value result = nullptr;
2526     const int32_t refCount = 1;
2527     napi_value resource = nullptr;
2528     size_t argc = ARGS_ONE;
2529     napi_value argv[ARGS_ONE] = {0};
2530     napi_value thisVar = nullptr;
2531 
2532     MediaLibraryTracer tracer;
2533     tracer.Start("JSGetActivePeers");
2534 
2535     GET_JS_ARGS(env, info, argc, argv, thisVar);
2536     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
2537     napi_get_undefined(env, &result);
2538 
2539     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2540     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2541     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2542         if (argc == ARGS_ONE) {
2543             GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
2544         }
2545 
2546         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2547         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSGetActivePeers", asyncContext);
2548         status = napi_create_async_work(
2549             env, nullptr, resource, [](napi_env env, void* data) {},
2550             reinterpret_cast<CompleteCallback>(JSGetActivePeersCompleteCallback),
2551             static_cast<void*>(asyncContext.get()), &asyncContext->work);
2552         if (status != napi_ok) {
2553             napi_get_undefined(env, &result);
2554         } else {
2555             napi_queue_async_work(env, asyncContext->work);
2556             asyncContext.release();
2557         }
2558     }
2559 
2560     return result;
2561 }
2562 
JSGetAllPeers(napi_env env,napi_callback_info info)2563 napi_value MediaLibraryNapi::JSGetAllPeers(napi_env env, napi_callback_info info)
2564 {
2565     napi_status status;
2566     napi_value result = nullptr;
2567     const int32_t refCount = 1;
2568     napi_value resource = nullptr;
2569     size_t argc = ARGS_ONE;
2570     napi_value argv[ARGS_ONE] = {0};
2571     napi_value thisVar = nullptr;
2572 
2573     MediaLibraryTracer tracer;
2574     tracer.Start("JSGetAllPeers");
2575 
2576     GET_JS_ARGS(env, info, argc, argv, thisVar);
2577     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
2578     napi_get_undefined(env, &result);
2579 
2580     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2581     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2582     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2583         if (argc == ARGS_ONE) {
2584             GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
2585         }
2586 
2587         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2588         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSGetAllPeers", asyncContext);
2589         status = napi_create_async_work(
2590             env, nullptr, resource, [](napi_env env, void* data) {},
2591             reinterpret_cast<CompleteCallback>(JSGetAllPeersCompleteCallback),
2592             static_cast<void*>(asyncContext.get()), &asyncContext->work);
2593         if (status != napi_ok) {
2594             napi_get_undefined(env, &result);
2595         } else {
2596             napi_queue_async_work(env, asyncContext->work);
2597             asyncContext.release();
2598         }
2599     }
2600 
2601     return result;
2602 }
2603 
CloseAsset(MediaLibraryAsyncContext * context,string uri)2604 static int32_t CloseAsset(MediaLibraryAsyncContext *context, string uri)
2605 {
2606     string abilityUri = MEDIALIBRARY_DATA_URI;
2607     Uri closeAssetUri(abilityUri + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CLOSEASSET);
2608     context->valuesBucket.Clear();
2609     context->valuesBucket.Put(MEDIA_DATA_DB_URI, uri);
2610     int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
2611     NAPI_DEBUG_LOG("File close asset %{public}d", ret);
2612     if (ret != E_SUCCESS) {
2613         context->error = ret;
2614         NAPI_ERR_LOG("File close asset fail, %{public}d", ret);
2615     }
2616     return ret;
2617 }
2618 
JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext * context)2619 static void JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext *context)
2620 {
2621     string realPath;
2622     if (!PathToRealPath(context->storeMediaSrc, realPath)) {
2623         NAPI_ERR_LOG("src path is not exist, %{public}d", errno);
2624         context->error = JS_ERR_NO_SUCH_FILE;
2625         return;
2626     }
2627     context->error = JS_E_RELATIVEPATH;
2628     int32_t srcFd = open(realPath.c_str(), O_RDWR);
2629     if (srcFd == -1) {
2630         NAPI_ERR_LOG("src path open fail, %{public}d", errno);
2631         return;
2632     }
2633     struct stat statSrc;
2634     if (fstat(srcFd, &statSrc) == -1) {
2635         close(srcFd);
2636         NAPI_DEBUG_LOG("File get stat failed, %{public}d", errno);
2637         return;
2638     }
2639     Uri createFileUri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET);
2640     int index = UserFileClient::Insert(createFileUri, context->valuesBucket);
2641     if (index < 0) {
2642         close(srcFd);
2643         NAPI_ERR_LOG("storeMedia fail, file already exist %{public}d", index);
2644         return;
2645     }
2646     getFileAssetById(index, "", context);
2647     Uri openFileUri(context->fileAsset->GetUri());
2648     int32_t destFd = UserFileClient::OpenFile(openFileUri, MEDIA_FILEMODE_READWRITE);
2649     if (destFd < 0) {
2650         context->error = destFd;
2651         NAPI_DEBUG_LOG("File open asset failed");
2652         close(srcFd);
2653         return;
2654     }
2655     if (sendfile(destFd, srcFd, nullptr, statSrc.st_size) == -1) {
2656         close(srcFd);
2657         close(destFd);
2658         CloseAsset(context, context->fileAsset->GetUri());
2659         NAPI_ERR_LOG("copy file fail %{public}d ", errno);
2660         return;
2661     }
2662     close(srcFd);
2663     close(destFd);
2664     CloseAsset(context, context->fileAsset->GetUri());
2665     context->error = ERR_DEFAULT;
2666 }
2667 
JSGetStoreMediaAssetCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2668 static void JSGetStoreMediaAssetCompleteCallback(napi_env env, napi_status status,
2669     MediaLibraryAsyncContext *context)
2670 {
2671     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2672     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2673     CHECK_NULL_PTR_RETURN_VOID(jsContext, "Async context is null");
2674     jsContext->status = false;
2675     napi_get_undefined(env, &jsContext->data);
2676     if (context->error != ERR_DEFAULT) {
2677         NAPI_ERR_LOG("JSGetStoreMediaAssetCompleteCallback failed %{public}d ", context->error);
2678         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2679             "storeMediaAsset fail");
2680     } else {
2681         napi_create_string_utf8(env, context->fileAsset->GetUri().c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
2682         jsContext->status = true;
2683         napi_get_undefined(env, &jsContext->error);
2684     }
2685 
2686     if (context->work != nullptr) {
2687         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2688                                                    context->work, *jsContext);
2689     }
2690     delete context;
2691 }
2692 
ConvertMediaType(const string & mimeType)2693 static int ConvertMediaType(const string &mimeType)
2694 {
2695     string res;
2696     // mimeType 'image/gif', 'video/mp4', 'audio/mp3', 'file/pdf'
2697     size_t slash = mimeType.find('/');
2698     if (slash != string::npos) {
2699         res = mimeType.substr(0, slash);
2700         if (res.empty()) {
2701             return MediaType::MEDIA_TYPE_FILE;
2702         }
2703     }
2704     if (res == "image") {
2705         return MediaType::MEDIA_TYPE_IMAGE;
2706     } else if (res == "video") {
2707         return MediaType::MEDIA_TYPE_VIDEO;
2708     } else if (res == "audio") {
2709         return MediaType::MEDIA_TYPE_AUDIO;
2710     }
2711     return MediaType::MEDIA_TYPE_FILE;
2712 }
2713 
GetStoreMediaAssetProper(napi_env env,napi_value param,const string & proper,string & res)2714 static bool GetStoreMediaAssetProper(napi_env env, napi_value param, const string &proper, string &res)
2715 {
2716     napi_value value = MediaLibraryNapiUtils::GetPropertyValueByName(env, param, proper.c_str());
2717     if (value == nullptr) {
2718         NAPI_ERR_LOG("GetPropertyValueByName %{public}s fail", proper.c_str());
2719         return false;
2720     }
2721     unique_ptr<char[]> tmp;
2722     bool succ;
2723     tie(succ, tmp, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, value);
2724     if (!succ) {
2725         NAPI_ERR_LOG("param %{public}s fail", proper.c_str());
2726         return false;
2727     }
2728     res = string(tmp.get());
2729     return true;
2730 }
2731 
GetDefaultDirectory(int mediaType)2732 static string GetDefaultDirectory(int mediaType)
2733 {
2734     string relativePath;
2735     if (mediaType == MediaType::MEDIA_TYPE_IMAGE) {
2736         relativePath = "Pictures/";
2737     } else if (mediaType == MediaType::MEDIA_TYPE_VIDEO) {
2738         relativePath = "Videos/";
2739     } else if (mediaType == MediaType::MEDIA_TYPE_AUDIO) {
2740         relativePath = "Audios/";
2741     } else {
2742         relativePath = "Documents/";
2743     }
2744     return relativePath;
2745 }
2746 
GetStoreMediaAssetArgs(napi_env env,napi_value param,MediaLibraryAsyncContext & asyncContext)2747 static napi_value GetStoreMediaAssetArgs(napi_env env, napi_value param,
2748     MediaLibraryAsyncContext &asyncContext)
2749 {
2750     auto context = &asyncContext;
2751     if (!GetStoreMediaAssetProper(env, param, "src", context->storeMediaSrc)) {
2752         NAPI_ERR_LOG("param get fail");
2753         return nullptr;
2754     }
2755     string fileName = MediaFileUtils::GetFilename(context->storeMediaSrc);
2756     if (fileName.empty() || (fileName.at(0) == '.')) {
2757         NAPI_ERR_LOG("src file name is not proper");
2758         context->error = JS_E_RELATIVEPATH;
2759         return nullptr;
2760     };
2761     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, fileName);
2762     string mimeType;
2763     if (!GetStoreMediaAssetProper(env, param, "mimeType", mimeType)) {
2764         NAPI_ERR_LOG("param get fail");
2765         return nullptr;
2766     }
2767     auto mediaType = ConvertMediaType(mimeType);
2768     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, mediaType);
2769     string relativePath;
2770     if (!GetStoreMediaAssetProper(env, param, "relativePath", relativePath)) {
2771         NAPI_DEBUG_LOG("optional relativePath param empty");
2772         relativePath = GetDefaultDirectory(mediaType);
2773     }
2774     context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, relativePath);
2775     NAPI_DEBUG_LOG("src:%{public}s mime:%{public}s relp:%{private}s filename:%{private}s",
2776         context->storeMediaSrc.c_str(), mimeType.c_str(), relativePath.c_str(), fileName.c_str());
2777     napi_value result = nullptr;
2778     napi_get_undefined(env, &result);
2779     return result;
2780 }
2781 
JSStoreMediaAsset(napi_env env,napi_callback_info info)2782 napi_value MediaLibraryNapi::JSStoreMediaAsset(napi_env env, napi_callback_info info)
2783 {
2784     size_t argc = ARGS_TWO;
2785     napi_value argv[ARGS_TWO] = {0};
2786     napi_value thisVar = nullptr;
2787     GET_JS_ARGS(env, info, argc, argv, thisVar);
2788     napi_value result = nullptr;
2789     napi_get_undefined(env, &result);
2790     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2791     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
2792     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2793     if ((status == napi_ok) && (asyncContext->objectInfo != nullptr)) {
2794         napi_value res = GetStoreMediaAssetArgs(env, argv[PARAM0], *asyncContext);
2795         CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, res, "Failed to obtain arguments");
2796         if (argc == ARGS_TWO) {
2797             const int32_t refCount = 1;
2798             GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
2799         }
2800         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2801         napi_value resource = nullptr;
2802         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStoreMediaAsset", asyncContext);
2803         status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
2804                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
2805                 JSGetStoreMediaAssetExecute(context);
2806             },
2807             reinterpret_cast<CompleteCallback>(JSGetStoreMediaAssetCompleteCallback),
2808             static_cast<void*>(asyncContext.get()), &asyncContext->work);
2809         if (status != napi_ok) {
2810             napi_get_undefined(env, &result);
2811         } else {
2812             napi_queue_async_work(env, asyncContext->work);
2813             asyncContext.release();
2814         }
2815     }
2816     return result;
2817 }
2818 
CreateAsyncCallbackInfo(napi_env env)2819 static Ability *CreateAsyncCallbackInfo(napi_env env)
2820 {
2821     if (env == nullptr) {
2822         NAPI_ERR_LOG("env == nullptr.");
2823         return nullptr;
2824     }
2825     napi_status ret;
2826     napi_value global = 0;
2827     const napi_extended_error_info *errorInfo = nullptr;
2828     ret = napi_get_global(env, &global);
2829     if (ret != napi_ok) {
2830         napi_get_last_error_info(env, &errorInfo);
2831         NAPI_ERR_LOG("get_global=%{public}d err:%{public}s", ret, errorInfo->error_message);
2832     }
2833     napi_value abilityObj = 0;
2834     ret = napi_get_named_property(env, global, "ability", &abilityObj);
2835     if (ret != napi_ok) {
2836         napi_get_last_error_info(env, &errorInfo);
2837         NAPI_ERR_LOG("get_named_property=%{public}d e:%{public}s", ret, errorInfo->error_message);
2838     }
2839     Ability *ability = nullptr;
2840     ret = napi_get_value_external(env, abilityObj, (void **)&ability);
2841     if (ret != napi_ok) {
2842         napi_get_last_error_info(env, &errorInfo);
2843         NAPI_ERR_LOG("get_value_external=%{public}d e:%{public}s", ret, errorInfo->error_message);
2844     }
2845     return ability;
2846 }
2847 
GetImagePreviewArgsUri(napi_env env,napi_value param,MediaLibraryAsyncContext & context)2848 static napi_value GetImagePreviewArgsUri(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
2849 {
2850     uint32_t arraySize = 0;
2851     if (!MediaLibraryNapiUtils::IsArrayForNapiValue(env, param, arraySize)) {
2852         NAPI_ERR_LOG("GetImagePreviewArgs get args fail, not array");
2853         return nullptr;
2854     }
2855     string uri = "";
2856     for (uint32_t i = 0; i < arraySize; i++) {
2857         napi_value jsValue = nullptr;
2858         if ((napi_get_element(env, param, i, &jsValue)) != napi_ok) {
2859             NAPI_ERR_LOG("GetImagePreviewArgs get args fail");
2860             return nullptr;
2861         }
2862         unique_ptr<char[]> inputStr;
2863         bool succ;
2864         tie(succ, inputStr, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, jsValue);
2865         if (!succ) {
2866             NAPI_ERR_LOG("GetImagePreviewArgs get string fail");
2867             return nullptr;
2868         }
2869         uri += string(inputStr.get());
2870         uri += ",";
2871     }
2872     context.uri = uri.substr(0, uri.length() - 1);
2873     NAPI_DEBUG_LOG("GetImagePreviewArgs res %{public}s", context.uri.c_str());
2874     napi_value res;
2875     napi_get_undefined(env, &res);
2876     return res;
2877 }
2878 
GetImagePreviewArgsNum(napi_env env,napi_value param,MediaLibraryAsyncContext & context)2879 static napi_value GetImagePreviewArgsNum(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
2880 {
2881     context.imagePreviewIndex = 0;
2882     napi_valuetype valueType = napi_undefined;
2883     napi_typeof(env, param, &valueType);
2884     if (valueType != napi_number) {
2885         NAPI_ERR_LOG("not napi value");
2886         return nullptr;
2887     }
2888     if (napi_get_value_int32(env, param, &context.imagePreviewIndex) != napi_ok) {
2889         NAPI_ERR_LOG("get property value fail");
2890     }
2891     NAPI_ERR_LOG("GetImagePreviewArgs num %{public}d", context.imagePreviewIndex);
2892     napi_value res;
2893     napi_get_undefined(env, &res);
2894     return res;
2895 }
2896 
JSStartImagePreviewExecute(MediaLibraryAsyncContext * context)2897 static void JSStartImagePreviewExecute(MediaLibraryAsyncContext *context)
2898 {
2899     if (context->ability_ == nullptr) {
2900         NAPI_ERR_LOG("ability_ is not exist");
2901         context->error = ERR_INVALID_OUTPUT;
2902         return;
2903     }
2904     Want want;
2905     string networkId = "";
2906     string bundleName = "com.ohos.photos";
2907     string abilityName = "com.ohos.photos.MainAbility";
2908     want.SetElementName(networkId, bundleName, abilityName);
2909     want.SetUri(context->uri);
2910     want.SetAction("ohos.want.action.viewData");
2911     want.SetParam("index", context->imagePreviewIndex);
2912     context->error = context->ability_->StartAbility(want);
2913 }
2914 
JSGetJSStartImagePreviewCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2915 static void JSGetJSStartImagePreviewCompleteCallback(napi_env env, napi_status status,
2916     MediaLibraryAsyncContext *context)
2917 {
2918     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2919     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2920     CHECK_NULL_PTR_RETURN_VOID(jsContext, "get jsContext failed");
2921     jsContext->status = true;
2922     napi_get_undefined(env, &jsContext->data);
2923     if (context->error != 0) {
2924         jsContext->status = false;
2925         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2926             "startImagePreview currently fail");
2927     }
2928     if (context->work != nullptr) {
2929         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2930                                                    context->work, *jsContext);
2931     }
2932     delete context;
2933 }
2934 
JSStartImagePreview(napi_env env,napi_callback_info info)2935 napi_value MediaLibraryNapi::JSStartImagePreview(napi_env env, napi_callback_info info)
2936 {
2937     size_t argc = ARGS_THREE;
2938     napi_value argv[ARGS_THREE] = {0};
2939     napi_value thisVar = nullptr;
2940     GET_JS_ARGS(env, info, argc, argv, thisVar);
2941     napi_value result = nullptr;
2942     napi_get_undefined(env, &result);
2943     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2944     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
2945     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2946     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2947         napi_value res = GetImagePreviewArgsUri(env, argv[PARAM0], *asyncContext);
2948         CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, result, "Failed to obtain arguments uri");
2949         GetImagePreviewArgsNum(env, argv[PARAM1], *asyncContext);
2950         asyncContext->ability_ = CreateAsyncCallbackInfo(env);
2951         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->ability_, result, "Failed to obtain ability");
2952         const int32_t refCount = 1;
2953         if (argc == ARGS_THREE) {
2954             GET_JS_ASYNC_CB_REF(env, argv[PARAM2], refCount, asyncContext->callbackRef);
2955         } else if (argc == ARGS_TWO && MediaLibraryNapiUtils::CheckJSArgsTypeAsFunc(env, argv[PARAM1])) {
2956             GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
2957         }
2958         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2959         napi_value resource = nullptr;
2960         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStartImagePreview", asyncContext);
2961         status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
2962                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
2963                 JSStartImagePreviewExecute(context);
2964             },
2965             reinterpret_cast<CompleteCallback>(JSGetJSStartImagePreviewCompleteCallback),
2966             static_cast<void*>(asyncContext.get()), &asyncContext->work);
2967         if (status != napi_ok) {
2968             napi_get_undefined(env, &result);
2969         } else {
2970             napi_queue_async_work(env, asyncContext->work);
2971             asyncContext.release();
2972         }
2973     }
2974     return result;
2975 }
2976 
ParseArgsCreateAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)2977 static napi_value ParseArgsCreateAsset(napi_env env, napi_callback_info info,
2978     unique_ptr<MediaLibraryAsyncContext> &context)
2979 {
2980     constexpr size_t minArgs = ARGS_ONE;
2981     constexpr size_t maxArgs = ARGS_THREE;
2982     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
2983         napi_ok, "Failed to get object info");
2984 
2985     /* Set mediaTypes to get typeMask */
2986     vector<uint32_t> mediaTypes;
2987     mediaTypes.push_back(MEDIA_TYPE_IMAGE);
2988     mediaTypes.push_back(MEDIA_TYPE_VIDEO);
2989     MediaLibraryNapiUtils::GenTypeMaskFromArray(mediaTypes, context->typeMask);
2990 
2991     /* Parse the first argument into displayName */
2992     string displayName;
2993     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
2994         napi_ok, "Failed to get displayName");
2995     MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
2996 
2997     /* Parse the second argument into albumUri if exists */
2998     string albumUri;
2999     if ((context->argc >= ARGS_TWO) &&
3000         (MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], albumUri) == napi_ok)) {
3001         context->valuesBucket.Put(MEDIA_DATA_DB_URI, albumUri);
3002     }
3003 
3004     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
3005     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
3006     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
3007         vector<uint32_t> types = { mediaType };
3008         MediaLibraryNapiUtils::GenTypeMaskFromArray(types, context->typeMask);
3009     }
3010 
3011     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok, "Failed to get callback");
3012 
3013     napi_value result = nullptr;
3014     NAPI_CALL(env, napi_get_boolean(env, true, &result));
3015     return result;
3016 }
3017 
AddDefaultFetchColumn(unique_ptr<MediaLibraryAsyncContext> & asyncContext)3018 void AddDefaultFetchColumn(unique_ptr<MediaLibraryAsyncContext> &asyncContext)
3019 {
3020     if (asyncContext->fetchColumn.size() == 0) {
3021         return;
3022     }
3023     asyncContext->fetchColumn.push_back(MEDIA_DATA_DB_ID);
3024     asyncContext->fetchColumn.push_back(MEDIA_DATA_DB_NAME);
3025     asyncContext->fetchColumn.push_back(MEDIA_DATA_DB_MEDIA_TYPE);
3026 }
3027 
UserFileMgrGetFileAssets(napi_env env,napi_callback_info info,vector<uint32_t> & mediaTypes)3028 napi_value UserFileMgrGetFileAssets(napi_env env, napi_callback_info info, vector<uint32_t> &mediaTypes)
3029 {
3030     napi_value ret = nullptr;
3031     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3032     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3033 
3034     // Parse the first argument into typeMask
3035     asyncContext->mediaTypes = mediaTypes;
3036     MediaLibraryNapiUtils::GenTypeMaskFromArray(mediaTypes, asyncContext->typeMask);
3037 
3038     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseAssetFetchOptCallback(env, info, asyncContext), asyncContext,
3039         JS_ERR_PARAMETER_INVALID);
3040     AddDefaultFetchColumn(asyncContext);
3041     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3042 
3043     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UFMJSGetTypeAssets", GetFileAssetsExecute,
3044         GetFileAssetsAsyncCallbackComplete);
3045 }
3046 
UserFileMgrGetPhotoAssets(napi_env env,napi_callback_info info)3047 napi_value MediaLibraryNapi::UserFileMgrGetPhotoAssets(napi_env env, napi_callback_info info)
3048 {
3049     vector<uint32_t> mediaTypes;
3050     mediaTypes.push_back(MEDIA_TYPE_IMAGE);
3051     mediaTypes.push_back(MEDIA_TYPE_VIDEO);
3052     return UserFileMgrGetFileAssets(env, info, mediaTypes);
3053 }
3054 
UserFileMgrGetAudioAssets(napi_env env,napi_callback_info info)3055 napi_value MediaLibraryNapi::UserFileMgrGetAudioAssets(napi_env env, napi_callback_info info)
3056 {
3057     vector<uint32_t> mediaTypes;
3058     mediaTypes.push_back(MEDIA_TYPE_AUDIO);
3059     return UserFileMgrGetFileAssets(env, info, mediaTypes);
3060 }
3061 
UserFileMgrGetAlbums(napi_env env,napi_callback_info info)3062 napi_value MediaLibraryNapi::UserFileMgrGetAlbums(napi_env env, napi_callback_info info)
3063 {
3064     napi_value ret = nullptr;
3065     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3066     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3067     // Parse the first argument into typeMask
3068     asyncContext->mediaTypes.push_back(MEDIA_TYPE_IMAGE);
3069     asyncContext->mediaTypes.push_back(MEDIA_TYPE_VIDEO);
3070     MediaLibraryNapiUtils::GenTypeMaskFromArray(asyncContext->mediaTypes, asyncContext->typeMask);
3071     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseAlbumFetchOptCallback(env, info, asyncContext), asyncContext,
3072         JS_ERR_PARAMETER_INVALID);
3073     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3074 
3075     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetAlbums", GetResultDataExecute,
3076         AlbumsAsyncCallbackComplete);
3077 }
3078 
UserFileMgrCreateAsset(napi_env env,napi_callback_info info)3079 napi_value MediaLibraryNapi::UserFileMgrCreateAsset(napi_env env, napi_callback_info info)
3080 {
3081     napi_value ret = nullptr;
3082     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3083     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3084     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3085     NAPI_ASSERT(env, ParseArgsCreateAsset(env, info, asyncContext), "Failed to parse js args");
3086 
3087     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCreateAsset", JSCreateAssetExecute,
3088         JSCreateAssetCompleteCallback);
3089 }
3090 
UserFileMgrTrashAsset(napi_env env,napi_callback_info info)3091 napi_value MediaLibraryNapi::UserFileMgrTrashAsset(napi_env env, napi_callback_info info)
3092 {
3093     napi_value ret = nullptr;
3094     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3095     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3096     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3097     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->uri),
3098         asyncContext, JS_ERR_PARAMETER_INVALID);
3099     MediaLibraryNapiUtils::GenTypeMaskFromArray({ MediaLibraryNapiUtils::GetMediaTypeFromUri(asyncContext->uri) },
3100         asyncContext->typeMask);
3101 
3102     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrTrashAsset", JSTrashAssetExecute,
3103         JSTrashAssetCompleteCallback);
3104 }
3105 
UserFileMgrGetPrivateAlbum(napi_env env,napi_callback_info info)3106 napi_value MediaLibraryNapi::UserFileMgrGetPrivateAlbum(napi_env env, napi_callback_info info)
3107 {
3108     napi_value ret = nullptr;
3109     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3110     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3111 
3112     CHECK_ARGS(env,  MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, asyncContext,
3113         asyncContext->privateAlbumType), asyncContext, JS_ERR_PARAMETER_INVALID);
3114     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3115     // PrivateAlbum only support image and video so far
3116     asyncContext->mediaTypes.push_back(MEDIA_TYPE_IMAGE);
3117     asyncContext->mediaTypes.push_back(MEDIA_TYPE_VIDEO);
3118     MediaLibraryNapiUtils::GenTypeMaskFromArray(asyncContext->mediaTypes, asyncContext->typeMask);
3119 
3120     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetPrivateAlbum",
3121         GetAllSmartAlbumResultDataExecute, GetPrivateAlbumCallbackComplete);
3122 }
3123 
CreateMediaTypeEnum(napi_env env)3124 napi_value MediaLibraryNapi::CreateMediaTypeEnum(napi_env env)
3125 {
3126     return CreateNumberEnumProperty(env, mediaTypesEnum, sMediaTypeEnumRef_);
3127 }
3128 
CreateMediaTypeUserFileEnum(napi_env env)3129 napi_value MediaLibraryNapi::CreateMediaTypeUserFileEnum(napi_env env)
3130 {
3131     const int32_t startIdx = 1;
3132     return CreateNumberEnumProperty(env, mediaTypesUserFileEnum, sMediaTypeEnumRef_, startIdx);
3133 }
3134 
CreateDirectoryTypeEnum(napi_env env)3135 napi_value MediaLibraryNapi::CreateDirectoryTypeEnum(napi_env env)
3136 {
3137     return CreateNumberEnumProperty(env, directoryEnum, sDirectoryEnumRef_);
3138 }
3139 
CreateVirtualAlbumTypeEnum(napi_env env)3140 napi_value MediaLibraryNapi::CreateVirtualAlbumTypeEnum(napi_env env)
3141 {
3142     return CreateNumberEnumProperty(env, virtualAlbumTypeEnum, sVirtualAlbumTypeEnumRef_);
3143 }
3144 
CreatePrivateAlbumTypeEnum(napi_env env)3145 napi_value MediaLibraryNapi::CreatePrivateAlbumTypeEnum(napi_env env)
3146 {
3147     return CreateNumberEnumProperty(env, privateAlbumTypeNameEnum, sPrivateAlbumEnumRef_);
3148 }
3149 
CreateFileKeyEnum(napi_env env)3150 napi_value MediaLibraryNapi::CreateFileKeyEnum(napi_env env)
3151 {
3152     return CreateStringEnumProperty(env, FILE_KEY_ENUM_PROPERTIES, sFileKeyEnumRef_);
3153 }
3154 
UserFileMgrCreateFileKeyEnum(napi_env env)3155 napi_value MediaLibraryNapi::UserFileMgrCreateFileKeyEnum(napi_env env)
3156 {
3157     return CreateStringEnumProperty(env, USERFILEMGR_FILEKEY_ENUM_PROPERTIES, sUserFileMgrFileKeyEnumRef_);
3158 }
3159 
CreateAudioKeyEnum(napi_env env)3160 napi_value MediaLibraryNapi::CreateAudioKeyEnum(napi_env env)
3161 {
3162     return CreateStringEnumProperty(env, AUDIOKEY_ENUM_PROPERTIES, sAudioKeyEnumRef_);
3163 }
3164 
CreateImageVideoKeyEnum(napi_env env)3165 napi_value MediaLibraryNapi::CreateImageVideoKeyEnum(napi_env env)
3166 {
3167     return CreateStringEnumProperty(env, IMAGEVIDEOKEY_ENUM_PROPERTIES, sImageVideoKeyEnumRef_);
3168 }
3169 
CreateAlbumKeyEnum(napi_env env)3170 napi_value MediaLibraryNapi::CreateAlbumKeyEnum(napi_env env)
3171 {
3172     return CreateStringEnumProperty(env, ALBUMKEY_ENUM_PROPERTIES, sAlbumKeyEnumRef_);
3173 }
3174 } // namespace Media
3175 } // namespace OHOS
3176